From 5669a18bd84f833e8597dc8da2ca532fb6e16d1c Mon Sep 17 00:00:00 2001 From: Vincent G <10739306+VinceOPS@users.noreply.github.com> Date: Sat, 22 Feb 2025 02:28:03 +0100 Subject: [PATCH 1/6] fix: typo in README_FR (#14179) (#14180) --- README_FR.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README_FR.md b/README_FR.md index 3890c2a996..afbf18b069 100644 --- a/README_FR.md +++ b/README_FR.md @@ -55,7 +55,7 @@ Dify est une plateforme de développement d'applications LLM open source. Son interface intuitive combine un flux de travail d'IA, un pipeline RAG, des capacités d'agent, une gestion de modèles, des fonctionnalités d'observabilité, et plus encore, vous permettant de passer rapidement du prototype à la production. Voici une liste des fonctionnalités principales:

-**1. Flux de travail**: +**1. Flux de travail** : Construisez et testez des flux de travail d'IA puissants sur un canevas visuel, en utilisant toutes les fonctionnalités suivantes et plus encore. @@ -63,27 +63,25 @@ Dify est une plateforme de développement d'applications LLM open source. Son in -**2. Prise en charge complète des modèles**: +**2. Prise en charge complète des modèles** : Intégration transparente avec des centaines de LLM propriétaires / open source provenant de dizaines de fournisseurs d'inférence et de solutions auto-hébergées, couvrant GPT, Mistral, Llama3, et tous les modèles compatibles avec l'API OpenAI. Une liste complète des fournisseurs de modèles pris en charge se trouve [ici](https://docs.dify.ai/getting-started/readme/model-providers). ![providers-v5](https://github.com/langgenius/dify/assets/13230914/5a17bdbe-097a-4100-8363-40255b70f6e3) -**3. IDE de prompt**: +**3. IDE de prompt** : Interface intuitive pour créer des prompts, comparer les performances des modèles et ajouter des fonctionnalités supplémentaires telles que la synthèse vocale à une application basée sur des chats. -**4. Pipeline RAG**: +**4. Pipeline RAG** : Des capacités RAG étendues qui couvrent tout, de l'ingestion de documents à la récupération, avec un support prêt à l'emploi pour l'extraction de texte à partir de PDF, PPT et autres formats de document courants. -**5. Capac - -ités d'agent**: +**5. Capacités d'agent** : Vous pouvez définir des agents basés sur l'appel de fonction LLM ou ReAct, et ajouter des outils pré-construits ou personnalisés pour l'agent. Dify fournit plus de 50 outils intégrés pour les agents d'IA, tels que la recherche Google, DALL·E, Stable Diffusion et WolframAlpha. -**6. LLMOps**: +**6. LLMOps** : Surveillez et analysez les journaux d'application et les performances au fil du temps. Vous pouvez continuellement améliorer les prompts, les ensembles de données et les modèles en fonction des données de production et des annotations. -**7. Backend-as-a-Service**: +**7. Backend-as-a-Service** : Toutes les offres de Dify sont accompagnées d'API correspondantes, vous permettant d'intégrer facilement Dify dans votre propre logique métier. From f55266731257e756b86638e6b9a83e924b9d0a52 Mon Sep 17 00:00:00 2001 From: Bowen Liang Date: Sun, 23 Feb 2025 13:46:48 +0800 Subject: [PATCH 2/6] chore: Simplify the unchanged overrided method in VariableAggregatorNode (#14175) --- .../variable_aggregator_node.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py b/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py index 031a7b8309..372496a8fa 100644 --- a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py +++ b/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py @@ -1,6 +1,3 @@ -from collections.abc import Mapping, Sequence -from typing import Any - from core.workflow.entities.node_entities import NodeRunResult from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType @@ -36,16 +33,3 @@ class VariableAggregatorNode(BaseNode[VariableAssignerNodeData]): break return NodeRunResult(status=WorkflowNodeExecutionStatus.SUCCEEDED, outputs=outputs, inputs=inputs) - - @classmethod - def _extract_variable_selector_to_variable_mapping( - cls, *, graph_config: Mapping[str, Any], node_id: str, node_data: VariableAssignerNodeData - ) -> Mapping[str, Sequence[str]]: - """ - Extract variable selector to variable mapping - :param graph_config: graph config - :param node_id: node id - :param node_data: node data - :return: - """ - return {} From 5ac0ef6253c1dc141fd01d3367621c1d03881945 Mon Sep 17 00:00:00 2001 From: Obada Khalili <54270856+obadakhalili@users.noreply.github.com> Date: Sun, 23 Feb 2025 07:47:03 +0200 Subject: [PATCH 3/6] Retain previous page's search params (#14176) --- web/app/(commonLayout)/apps/Apps.tsx | 12 +++++++++--- .../(commonLayout)/apps/hooks/useAppsQueryState.ts | 11 +++++++++-- web/app/components/header/nav/index.tsx | 14 +++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/web/app/(commonLayout)/apps/Apps.tsx b/web/app/(commonLayout)/apps/Apps.tsx index 34a28d908e..463e9cf515 100644 --- a/web/app/(commonLayout)/apps/Apps.tsx +++ b/web/app/(commonLayout)/apps/Apps.tsx @@ -59,8 +59,8 @@ const Apps = () => { const [activeTab, setActiveTab] = useTabSearchParams({ defaultTab: 'all', }) - const { query: { tagIDs = [], keywords = '' }, setQuery } = useAppsQueryState() - const [isCreatedByMe, setIsCreatedByMe] = useState(false) + const { query: { tagIDs = [], keywords = '', isCreatedByMe: queryIsCreatedByMe = false }, setQuery } = useAppsQueryState() + const [isCreatedByMe, setIsCreatedByMe] = useState(queryIsCreatedByMe) const [tagFilterValue, setTagFilterValue] = useState(tagIDs) const [searchKeywords, setSearchKeywords] = useState(keywords) const setKeywords = useCallback((keywords: string) => { @@ -126,6 +126,12 @@ const Apps = () => { handleTagsUpdate() } + const handleCreatedByMeChange = useCallback(() => { + const newValue = !isCreatedByMe + setIsCreatedByMe(newValue) + setQuery(prev => ({ ...prev, isCreatedByMe: newValue })) + }, [isCreatedByMe, setQuery]) + return ( <>
@@ -139,7 +145,7 @@ const Apps = () => { className='mr-2' label={t('app.showMyCreatedAppsOnly')} isChecked={isCreatedByMe} - onChange={() => setIsCreatedByMe(!isCreatedByMe)} + onChange={handleCreatedByMeChange} /> 0) current.set('tagIDs', tagIDs.join(';')) @@ -26,6 +28,11 @@ function updateSearchParams(query: AppsQuery, current: URLSearchParams) { current.set('keywords', keywords) else current.delete('keywords') + + if (isCreatedByMe) + current.set('isCreatedByMe', 'true') + else + current.delete('isCreatedByMe') } function useAppsQueryState() { diff --git a/web/app/components/header/nav/index.tsx b/web/app/components/header/nav/index.tsx index de98593ddd..b7ee7b6973 100644 --- a/web/app/components/header/nav/index.tsx +++ b/web/app/components/header/nav/index.tsx @@ -1,8 +1,8 @@ 'use client' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import Link from 'next/link' -import { useSelectedLayoutSegment } from 'next/navigation' +import { usePathname, useSearchParams, useSelectedLayoutSegment } from 'next/navigation' import type { INavSelectorProps } from './nav-selector' import NavSelector from './nav-selector' import classNames from '@/utils/classnames' @@ -35,6 +35,14 @@ const Nav = ({ 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 (
- +
setAppDetail()} className={classNames(` From 2ace9ae4e4cb7da5bfc1ea34635dc695133fc16b Mon Sep 17 00:00:00 2001 From: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Date: Sun, 23 Feb 2025 19:35:10 +0800 Subject: [PATCH 4/6] fix: add responsive layout for file uploader in datasets (#14159) --- .../datasets/create/file-uploader/index.tsx | 2 +- .../datasets/create/step-one/index.module.css | 4 ++-- .../datasets/create/step-one/index.tsx | 23 +++++++++++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/web/app/components/datasets/create/file-uploader/index.tsx b/web/app/components/datasets/create/file-uploader/index.tsx index e42a24cfef..5a64c319cd 100644 --- a/web/app/components/datasets/create/file-uploader/index.tsx +++ b/web/app/components/datasets/create/file-uploader/index.tsx @@ -243,7 +243,7 @@ const FileUploader = ({ }, [handleDrop]) return ( -
+
{!hideUpload && ( +
- {t('datasetCreation.stepOne.dataSourceType.file')} + + {t('datasetCreation.stepOne.dataSourceType.file')} +
- {t('datasetCreation.stepOne.dataSourceType.notion')} + + {t('datasetCreation.stepOne.dataSourceType.notion')} +
changeType(DataSourceType.WEB)} > - {t('datasetCreation.stepOne.dataSourceType.web')} + + {t('datasetCreation.stepOne.dataSourceType.web')} +
) From 3942e45cab802dbe4425de3efe964126774b9e00 Mon Sep 17 00:00:00 2001 From: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Date: Mon, 24 Feb 2025 10:49:43 +0800 Subject: [PATCH 5/6] fix: update refresh logic for plugin list to avoid redundant request and fix model provider list update issue in settings (#14152) --- .../hooks/use-refresh-plugin-list.tsx | 8 +++----- web/service/use-plugins.ts | 20 ++++++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/web/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx b/web/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx index bb6c1baedb..ac26971359 100644 --- a/web/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx +++ b/web/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx @@ -23,17 +23,15 @@ const useRefreshPluginList = () => { // installed list invalidateInstalledPluginList() - if (!manifest) return - // tool page, tool select - if (PluginType.tool.includes(manifest.category) || refreshAllType) { + 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 (PluginType.model.includes(manifest.category) || refreshAllType) { + if ((manifest && PluginType.model.includes(manifest.category)) || refreshAllType) { refreshModelProviders() refetchLLMModelList() refetchEmbeddingModelList() @@ -41,7 +39,7 @@ const useRefreshPluginList = () => { } // agent select - if (PluginType.agent.includes(manifest.category) || refreshAllType) + if ((manifest && PluginType.agent.includes(manifest.category)) || refreshAllType) invalidateStrategyProviders() }, } diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index e05ae37c88..63e7a053ab 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useEffect } from 'react' import type { ModelProvider, } from '@/app/components/header/account-setting/model-provider-page/declarations' @@ -39,6 +39,7 @@ import { useInvalidateAllBuiltInTools } from './use-tools' import usePermission from '@/app/components/plugins/plugin-page/use-permission' import { uninstallPlugin } from '@/service/plugins' import useRefreshPluginList from '@/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list' +import { cloneDeep } from 'lodash-es' const NAME_SPACE = 'plugins' @@ -383,6 +384,7 @@ export const usePluginTaskList = (category?: PluginType) => { const { data, isFetched, + isRefetching, refetch, ...rest } = useQuery({ @@ -392,16 +394,24 @@ export const usePluginTaskList = (category?: PluginType) => { refetchInterval: (lastQuery) => { const lastData = lastQuery.state.data const taskDone = lastData?.tasks.every(task => task.status === TaskStatus.success || task.status === TaskStatus.failed) + return taskDone ? false : 5000 + }, + }) + + useEffect(() => { + // After first fetch, refresh plugin list each time all tasks are done + if (!isRefetching) { + const lastData = cloneDeep(data) + const taskDone = lastData?.tasks.every(task => task.status === TaskStatus.success || task.status === TaskStatus.failed) const taskAllFailed = lastData?.tasks.every(task => task.status === TaskStatus.failed) if (taskDone) { if (lastData?.tasks.length && !taskAllFailed) refreshPluginList(category ? { category } as any : undefined, !category) - return false } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isRefetching]) - return 5000 - }, - }) const handleRefetch = useCallback(() => { refetch() }, [refetch]) From 7790214620c653a6f6c19c402969a0474a3e5778 Mon Sep 17 00:00:00 2001 From: Onelevenvy <49232224+Onelevenvy@users.noreply.github.com> Date: Mon, 24 Feb 2025 11:32:09 +0800 Subject: [PATCH 6/6] chore: Fix typos in simplified and traditional Chinese in i18n files (#14228) --- web/i18n/zh-Hans/app-overview.ts | 6 +++--- web/i18n/zh-Hans/billing.ts | 2 +- web/i18n/zh-Hans/run-log.ts | 2 +- web/i18n/zh-Hant/app-overview.ts | 6 +++--- web/i18n/zh-Hant/billing.ts | 2 +- web/i18n/zh-Hant/run-log.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/web/i18n/zh-Hans/app-overview.ts b/web/i18n/zh-Hans/app-overview.ts index 6274a64f13..5232fc0c63 100644 --- a/web/i18n/zh-Hans/app-overview.ts +++ b/web/i18n/zh-Hans/app-overview.ts @@ -148,15 +148,15 @@ const translation = { }, avgSessionInteractions: { title: '平均会话互动数', - explanation: '反应每个会话用户的持续沟通次数,如果用户与 AI 问答了 10 轮,即为 10。该指标反映了用户粘性。仅在对话型应用提供。', + explanation: '反映每个会话用户的持续沟通次数,如果用户与 AI 问答了 10 轮,即为 10。该指标反映了用户粘性。仅在对话型应用提供。', }, avgUserInteractions: { title: '平均用户调用次数', - explanation: '反应每天用户的使用次数。该指标反映了用户粘性。', + explanation: '反映每天用户的使用次数。该指标反映了用户粘性。', }, userSatisfactionRate: { title: '用户满意度', - explanation: '每 1000 条消息的点赞数。反应了用户对回答十分满意的比例。', + explanation: '每 1000 条消息的点赞数。反映了用户对回答十分满意的比例。', }, avgResponseTime: { title: '平均响应时间', diff --git a/web/i18n/zh-Hans/billing.ts b/web/i18n/zh-Hans/billing.ts index bc20839abc..84bcac6590 100644 --- a/web/i18n/zh-Hans/billing.ts +++ b/web/i18n/zh-Hans/billing.ts @@ -52,7 +52,7 @@ const translation = { communityForums: '社区论坛', emailSupport: '电子邮件支持', priorityEmail: '优先电子邮件和聊天支持', - logoChange: 'Logo更改', + logoChange: 'Logo 更改', SSOAuthentication: 'SSO 认证', personalizedSupport: '个性化支持', dedicatedAPISupport: '专用 API 支持', diff --git a/web/i18n/zh-Hans/run-log.ts b/web/i18n/zh-Hans/run-log.ts index dc93e9aeb0..0cf49b03fd 100644 --- a/web/i18n/zh-Hans/run-log.ts +++ b/web/i18n/zh-Hans/run-log.ts @@ -19,7 +19,7 @@ const translation = { steps: '运行步数', }, resultEmpty: { - title: '本次运行仅输出JSON格式,', + title: '本次运行仅输出 JSON 格式,', tipLeft: '请转到', link: '详细信息面板', tipRight: '查看它。', diff --git a/web/i18n/zh-Hant/app-overview.ts b/web/i18n/zh-Hant/app-overview.ts index 956fa9a1c9..e7870d90c7 100644 --- a/web/i18n/zh-Hant/app-overview.ts +++ b/web/i18n/zh-Hant/app-overview.ts @@ -148,15 +148,15 @@ const translation = { }, avgSessionInteractions: { title: '平均會話互動數', - explanation: '反應每個會話使用者的持續溝通次數,如果使用者與 AI 問答了 10 輪,即為 10。該指標反映了使用者粘性。僅在對話型應用提供。', + explanation: '反映每個會話使用者的持續溝通次數,如果使用者與 AI 問答了 10 輪,即為 10。該指標反映了使用者粘性。僅在對話型應用提供。', }, avgUserInteractions: { title: '平均使用者呼叫次數', - explanation: '反應每天使用者的使用次數。該指標反映了使用者粘性。', + explanation: '反映每天使用者的使用次數。該指標反映了使用者粘性。', }, userSatisfactionRate: { title: '使用者滿意度', - explanation: '每 1000 條訊息的點贊數。反應了使用者對回答十分滿意的比例。', + explanation: '每 1000 條訊息的點贊數。反映了使用者對回答十分滿意的比例。', }, avgResponseTime: { title: '平均響應時間', diff --git a/web/i18n/zh-Hant/billing.ts b/web/i18n/zh-Hant/billing.ts index f318b6fa66..208102c5be 100644 --- a/web/i18n/zh-Hant/billing.ts +++ b/web/i18n/zh-Hant/billing.ts @@ -51,7 +51,7 @@ const translation = { communityForums: '社群論壇', emailSupport: '電子郵件支援', priorityEmail: '優先電子郵件和聊天支援', - logoChange: 'Logo更改', + logoChange: 'Logo 更改', SSOAuthentication: 'SSO 認證', personalizedSupport: '個性化支援', dedicatedAPISupport: '專用 API 支援', diff --git a/web/i18n/zh-Hant/run-log.ts b/web/i18n/zh-Hant/run-log.ts index a22ebf8a53..c3bfb54731 100644 --- a/web/i18n/zh-Hant/run-log.ts +++ b/web/i18n/zh-Hant/run-log.ts @@ -19,7 +19,7 @@ const translation = { steps: '執行步數', }, resultEmpty: { - title: '本運行僅輸出JSON格式,', + title: '本運行僅輸出 JSON 格式,', tipLeft: '請到', link: '詳細資訊面板', tipRight: '查看它。',