| @@ -1,3 +1,4 @@ | |||
| from pydantic import computed_field | |||
| from pydantic_settings import BaseSettings, SettingsConfigDict | |||
| from configs.deploy import DeploymentConfig | |||
| @@ -43,3 +44,28 @@ class DifyConfig( | |||
| # ignore extra attributes | |||
| extra='ignore', | |||
| ) | |||
| CODE_MAX_NUMBER: int = 9223372036854775807 | |||
| CODE_MIN_NUMBER: int = -9223372036854775808 | |||
| CODE_MAX_STRING_LENGTH: int = 80000 | |||
| CODE_MAX_STRING_ARRAY_LENGTH: int = 30 | |||
| CODE_MAX_OBJECT_ARRAY_LENGTH: int = 30 | |||
| CODE_MAX_NUMBER_ARRAY_LENGTH: int = 1000 | |||
| HTTP_REQUEST_MAX_CONNECT_TIMEOUT: int = 300 | |||
| HTTP_REQUEST_MAX_READ_TIMEOUT: int = 600 | |||
| HTTP_REQUEST_MAX_WRITE_TIMEOUT: int = 600 | |||
| HTTP_REQUEST_NODE_MAX_BINARY_SIZE: int = 1024 * 1024 * 10 | |||
| @computed_field | |||
| def HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE(self) -> str: | |||
| return f'{self.HTTP_REQUEST_NODE_MAX_BINARY_SIZE / 1024 / 1024:.2f}MB' | |||
| HTTP_REQUEST_NODE_MAX_TEXT_SIZE: int = 1024 * 1024 | |||
| @computed_field | |||
| def HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE(self) -> str: | |||
| return f'{self.HTTP_REQUEST_NODE_MAX_TEXT_SIZE / 1024 / 1024:.2f}MB' | |||
| SSRF_PROXY_HTTP_URL: str | None = None | |||
| SSRF_PROXY_HTTPS_URL: str | None = None | |||
| @@ -6,6 +6,7 @@ from flask_login import current_user | |||
| from flask_restful import Resource | |||
| from werkzeug.exceptions import Forbidden | |||
| from configs import dify_config | |||
| from controllers.console import api | |||
| from libs.login import login_required | |||
| from libs.oauth_data_source import NotionOAuth | |||
| @@ -16,11 +17,11 @@ from ..wraps import account_initialization_required | |||
| def get_oauth_providers(): | |||
| with current_app.app_context(): | |||
| notion_oauth = NotionOAuth(client_id=current_app.config.get('NOTION_CLIENT_ID'), | |||
| client_secret=current_app.config.get( | |||
| 'NOTION_CLIENT_SECRET'), | |||
| redirect_uri=current_app.config.get( | |||
| 'CONSOLE_API_URL') + '/console/api/oauth/data-source/callback/notion') | |||
| if not dify_config.NOTION_CLIENT_ID or not dify_config.NOTION_CLIENT_SECRET: | |||
| return {} | |||
| notion_oauth = NotionOAuth(client_id=dify_config.NOTION_CLIENT_ID, | |||
| client_secret=dify_config.NOTION_CLIENT_SECRET, | |||
| redirect_uri=dify_config.CONSOLE_API_URL + '/console/api/oauth/data-source/callback/notion') | |||
| OAUTH_PROVIDERS = { | |||
| 'notion': notion_oauth | |||
| @@ -39,8 +40,10 @@ class OAuthDataSource(Resource): | |||
| print(vars(oauth_provider)) | |||
| if not oauth_provider: | |||
| return {'error': 'Invalid provider'}, 400 | |||
| if current_app.config.get('NOTION_INTEGRATION_TYPE') == 'internal': | |||
| internal_secret = current_app.config.get('NOTION_INTERNAL_SECRET') | |||
| if dify_config.NOTION_INTEGRATION_TYPE == 'internal': | |||
| internal_secret = dify_config.NOTION_INTERNAL_SECRET | |||
| if not internal_secret: | |||
| return {'error': 'Internal secret is not set'}, | |||
| oauth_provider.save_internal_access_token(internal_secret) | |||
| return { 'data': '' } | |||
| else: | |||
| @@ -60,13 +63,13 @@ class OAuthDataSourceCallback(Resource): | |||
| if 'code' in request.args: | |||
| code = request.args.get('code') | |||
| return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&code={code}') | |||
| return redirect(f'{dify_config.CONSOLE_WEB_URL}?type=notion&code={code}') | |||
| elif 'error' in request.args: | |||
| error = request.args.get('error') | |||
| return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&error={error}') | |||
| return redirect(f'{dify_config.CONSOLE_WEB_URL}?type=notion&error={error}') | |||
| else: | |||
| return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&error=Access denied') | |||
| return redirect(f'{dify_config.CONSOLE_WEB_URL}?type=notion&error=Access denied') | |||
| class OAuthDataSourceBinding(Resource): | |||
| @@ -1,7 +1,7 @@ | |||
| from typing import cast | |||
| import flask_login | |||
| from flask import current_app, request | |||
| from flask import request | |||
| from flask_restful import Resource, reqparse | |||
| import services | |||
| @@ -56,14 +56,14 @@ class LogoutApi(Resource): | |||
| class ResetPasswordApi(Resource): | |||
| @setup_required | |||
| def get(self): | |||
| parser = reqparse.RequestParser() | |||
| parser.add_argument('email', type=email, required=True, location='json') | |||
| args = parser.parse_args() | |||
| # parser = reqparse.RequestParser() | |||
| # parser.add_argument('email', type=email, required=True, location='json') | |||
| # args = parser.parse_args() | |||
| # import mailchimp_transactional as MailchimpTransactional | |||
| # from mailchimp_transactional.api_client import ApiClientError | |||
| account = {'email': args['email']} | |||
| # account = {'email': args['email']} | |||
| # account = AccountService.get_by_email(args['email']) | |||
| # if account is None: | |||
| # raise ValueError('Email not found') | |||
| @@ -71,22 +71,22 @@ class ResetPasswordApi(Resource): | |||
| # AccountService.update_password(account, new_password) | |||
| # todo: Send email | |||
| MAILCHIMP_API_KEY = current_app.config['MAILCHIMP_TRANSACTIONAL_API_KEY'] | |||
| # MAILCHIMP_API_KEY = current_app.config['MAILCHIMP_TRANSACTIONAL_API_KEY'] | |||
| # mailchimp = MailchimpTransactional(MAILCHIMP_API_KEY) | |||
| message = { | |||
| 'from_email': 'noreply@example.com', | |||
| 'to': [{'email': account.email}], | |||
| 'subject': 'Reset your Dify password', | |||
| 'html': """ | |||
| <p>Dear User,</p> | |||
| <p>The Dify team has generated a new password for you, details as follows:</p> | |||
| <p><strong>{new_password}</strong></p> | |||
| <p>Please change your password to log in as soon as possible.</p> | |||
| <p>Regards,</p> | |||
| <p>The Dify Team</p> | |||
| """ | |||
| } | |||
| # message = { | |||
| # 'from_email': 'noreply@example.com', | |||
| # 'to': [{'email': account['email']}], | |||
| # 'subject': 'Reset your Dify password', | |||
| # 'html': """ | |||
| # <p>Dear User,</p> | |||
| # <p>The Dify team has generated a new password for you, details as follows:</p> | |||
| # <p><strong>{new_password}</strong></p> | |||
| # <p>Please change your password to log in as soon as possible.</p> | |||
| # <p>Regards,</p> | |||
| # <p>The Dify Team</p> | |||
| # """ | |||
| # } | |||
| # response = mailchimp.messages.send({ | |||
| # 'message': message, | |||
| @@ -6,6 +6,7 @@ import requests | |||
| from flask import current_app, redirect, request | |||
| from flask_restful import Resource | |||
| from configs import dify_config | |||
| from constants.languages import languages | |||
| from extensions.ext_database import db | |||
| from libs.helper import get_remote_ip | |||
| @@ -18,22 +19,24 @@ from .. import api | |||
| def get_oauth_providers(): | |||
| with current_app.app_context(): | |||
| github_oauth = GitHubOAuth(client_id=current_app.config.get('GITHUB_CLIENT_ID'), | |||
| client_secret=current_app.config.get( | |||
| 'GITHUB_CLIENT_SECRET'), | |||
| redirect_uri=current_app.config.get( | |||
| 'CONSOLE_API_URL') + '/console/api/oauth/authorize/github') | |||
| google_oauth = GoogleOAuth(client_id=current_app.config.get('GOOGLE_CLIENT_ID'), | |||
| client_secret=current_app.config.get( | |||
| 'GOOGLE_CLIENT_SECRET'), | |||
| redirect_uri=current_app.config.get( | |||
| 'CONSOLE_API_URL') + '/console/api/oauth/authorize/google') | |||
| OAUTH_PROVIDERS = { | |||
| 'github': github_oauth, | |||
| 'google': google_oauth | |||
| } | |||
| if not dify_config.GITHUB_CLIENT_ID or not dify_config.GITHUB_CLIENT_SECRET: | |||
| github_oauth = None | |||
| else: | |||
| github_oauth = GitHubOAuth( | |||
| client_id=dify_config.GITHUB_CLIENT_ID, | |||
| client_secret=dify_config.GITHUB_CLIENT_SECRET, | |||
| redirect_uri=dify_config.CONSOLE_API_URL + '/console/api/oauth/authorize/github', | |||
| ) | |||
| if not dify_config.GOOGLE_CLIENT_ID or not dify_config.GOOGLE_CLIENT_SECRET: | |||
| google_oauth = None | |||
| else: | |||
| google_oauth = GoogleOAuth( | |||
| client_id=dify_config.GOOGLE_CLIENT_ID, | |||
| client_secret=dify_config.GOOGLE_CLIENT_SECRET, | |||
| redirect_uri=dify_config.CONSOLE_API_URL + '/console/api/oauth/authorize/google', | |||
| ) | |||
| OAUTH_PROVIDERS = {'github': github_oauth, 'google': google_oauth} | |||
| return OAUTH_PROVIDERS | |||
| @@ -63,8 +66,7 @@ class OAuthCallback(Resource): | |||
| token = oauth_provider.get_access_token(code) | |||
| user_info = oauth_provider.get_user_info(token) | |||
| except requests.exceptions.HTTPError as e: | |||
| logging.exception( | |||
| f"An error occurred during the OAuth process with {provider}: {e.response.text}") | |||
| logging.exception(f'An error occurred during the OAuth process with {provider}: {e.response.text}') | |||
| return {'error': 'OAuth process failed'}, 400 | |||
| account = _generate_account(provider, user_info) | |||
| @@ -81,7 +83,7 @@ class OAuthCallback(Resource): | |||
| token = AccountService.login(account, ip_address=get_remote_ip(request)) | |||
| return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?console_token={token}') | |||
| return redirect(f'{dify_config.CONSOLE_WEB_URL}?console_token={token}') | |||
| def _get_account_by_openid_or_email(provider: str, user_info: OAuthUserInfo) -> Optional[Account]: | |||
| @@ -101,11 +103,7 @@ def _generate_account(provider: str, user_info: OAuthUserInfo): | |||
| # Create account | |||
| account_name = user_info.name if user_info.name else 'Dify' | |||
| account = RegisterService.register( | |||
| email=user_info.email, | |||
| name=account_name, | |||
| password=None, | |||
| open_id=user_info.id, | |||
| provider=provider | |||
| email=user_info.email, name=account_name, password=None, open_id=user_info.id, provider=provider | |||
| ) | |||
| # Set interface language | |||
| @@ -1,7 +1,6 @@ | |||
| import os | |||
| import requests | |||
| from configs import dify_config | |||
| from models.api_based_extension import APIBasedExtensionPoint | |||
| @@ -31,10 +30,10 @@ class APIBasedExtensionRequestor: | |||
| try: | |||
| # proxy support for security | |||
| proxies = None | |||
| if os.environ.get("SSRF_PROXY_HTTP_URL") and os.environ.get("SSRF_PROXY_HTTPS_URL"): | |||
| if dify_config.SSRF_PROXY_HTTP_URL and dify_config.SSRF_PROXY_HTTPS_URL: | |||
| proxies = { | |||
| 'http': os.environ.get("SSRF_PROXY_HTTP_URL"), | |||
| 'https': os.environ.get("SSRF_PROXY_HTTPS_URL"), | |||
| 'http': dify_config.SSRF_PROXY_HTTP_URL, | |||
| 'https': dify_config.SSRF_PROXY_HTTPS_URL, | |||
| } | |||
| response = requests.request( | |||
| @@ -1,5 +1,4 @@ | |||
| import logging | |||
| import os | |||
| import time | |||
| from enum import Enum | |||
| from threading import Lock | |||
| @@ -9,6 +8,7 @@ from httpx import get, post | |||
| from pydantic import BaseModel | |||
| from yarl import URL | |||
| from configs import dify_config | |||
| from core.helper.code_executor.entities import CodeDependency | |||
| from core.helper.code_executor.javascript.javascript_transformer import NodeJsTemplateTransformer | |||
| from core.helper.code_executor.jinja2.jinja2_transformer import Jinja2TemplateTransformer | |||
| @@ -18,8 +18,8 @@ from core.helper.code_executor.template_transformer import TemplateTransformer | |||
| logger = logging.getLogger(__name__) | |||
| # Code Executor | |||
| CODE_EXECUTION_ENDPOINT = os.environ.get('CODE_EXECUTION_ENDPOINT', 'http://sandbox:8194') | |||
| CODE_EXECUTION_API_KEY = os.environ.get('CODE_EXECUTION_API_KEY', 'dify-sandbox') | |||
| CODE_EXECUTION_ENDPOINT = dify_config.CODE_EXECUTION_ENDPOINT | |||
| CODE_EXECUTION_API_KEY = dify_config.CODE_EXECUTION_API_KEY | |||
| CODE_EXECUTION_TIMEOUT= (10, 60) | |||
| @@ -29,10 +29,8 @@ class ZhipuAI(HttpClient): | |||
| http_client: httpx.Client | None = None, | |||
| custom_headers: Mapping[str, str] | None = None | |||
| ) -> None: | |||
| # if api_key is None: | |||
| # api_key = os.environ.get("ZHIPUAI_API_KEY") | |||
| if api_key is None: | |||
| raise ZhipuAIError("未提供api_key,请通过参数或环境变量提供") | |||
| raise ZhipuAIError("No api_key provided, please provide it through parameters or environment variables") | |||
| self.api_key = api_key | |||
| if base_url is None: | |||
| @@ -1,6 +1,6 @@ | |||
| import os | |||
| from typing import Optional, Union, cast | |||
| from configs import dify_config | |||
| from core.helper.code_executor.code_executor import CodeExecutionException, CodeExecutor, CodeLanguage | |||
| from core.helper.code_executor.code_node_provider import CodeNodeProvider | |||
| from core.helper.code_executor.javascript.javascript_code_provider import JavascriptCodeProvider | |||
| @@ -11,14 +11,14 @@ from core.workflow.nodes.base_node import BaseNode | |||
| from core.workflow.nodes.code.entities import CodeNodeData | |||
| from models.workflow import WorkflowNodeExecutionStatus | |||
| MAX_NUMBER = int(os.environ.get('CODE_MAX_NUMBER', '9223372036854775807')) | |||
| MIN_NUMBER = int(os.environ.get('CODE_MIN_NUMBER', '-9223372036854775808')) | |||
| MAX_NUMBER = dify_config.CODE_MAX_NUMBER | |||
| MIN_NUMBER = dify_config.CODE_MIN_NUMBER | |||
| MAX_PRECISION = 20 | |||
| MAX_DEPTH = 5 | |||
| MAX_STRING_LENGTH = int(os.environ.get('CODE_MAX_STRING_LENGTH', '80000')) | |||
| MAX_STRING_ARRAY_LENGTH = int(os.environ.get('CODE_MAX_STRING_ARRAY_LENGTH', '30')) | |||
| MAX_OBJECT_ARRAY_LENGTH = int(os.environ.get('CODE_MAX_OBJECT_ARRAY_LENGTH', '30')) | |||
| MAX_NUMBER_ARRAY_LENGTH = int(os.environ.get('CODE_MAX_NUMBER_ARRAY_LENGTH', '1000')) | |||
| MAX_STRING_LENGTH = dify_config.CODE_MAX_STRING_LENGTH | |||
| MAX_STRING_ARRAY_LENGTH = dify_config.CODE_MAX_STRING_ARRAY_LENGTH | |||
| MAX_OBJECT_ARRAY_LENGTH = dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH | |||
| MAX_NUMBER_ARRAY_LENGTH = dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH | |||
| class CodeNode(BaseNode): | |||
| @@ -1,13 +1,13 @@ | |||
| import os | |||
| from typing import Literal, Optional, Union | |||
| from pydantic import BaseModel, ValidationInfo, field_validator | |||
| from configs import dify_config | |||
| from core.workflow.entities.base_node_data_entities import BaseNodeData | |||
| MAX_CONNECT_TIMEOUT = int(os.environ.get('HTTP_REQUEST_MAX_CONNECT_TIMEOUT', '300')) | |||
| MAX_READ_TIMEOUT = int(os.environ.get('HTTP_REQUEST_MAX_READ_TIMEOUT', '600')) | |||
| MAX_WRITE_TIMEOUT = int(os.environ.get('HTTP_REQUEST_MAX_WRITE_TIMEOUT', '600')) | |||
| MAX_CONNECT_TIMEOUT = dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT | |||
| MAX_READ_TIMEOUT = dify_config.HTTP_REQUEST_MAX_READ_TIMEOUT | |||
| MAX_WRITE_TIMEOUT = dify_config.HTTP_REQUEST_MAX_WRITE_TIMEOUT | |||
| class HttpRequestNodeAuthorizationConfig(BaseModel): | |||
| @@ -1,5 +1,4 @@ | |||
| import json | |||
| import os | |||
| from copy import deepcopy | |||
| from random import randint | |||
| from typing import Any, Optional, Union | |||
| @@ -8,6 +7,7 @@ from urllib.parse import urlencode | |||
| import httpx | |||
| import core.helper.ssrf_proxy as ssrf_proxy | |||
| from configs import dify_config | |||
| from core.workflow.entities.variable_entities import VariableSelector | |||
| from core.workflow.entities.variable_pool import ValueType, VariablePool | |||
| from core.workflow.nodes.http_request.entities import ( | |||
| @@ -18,10 +18,10 @@ from core.workflow.nodes.http_request.entities import ( | |||
| ) | |||
| from core.workflow.utils.variable_template_parser import VariableTemplateParser | |||
| MAX_BINARY_SIZE = int(os.environ.get('HTTP_REQUEST_NODE_MAX_BINARY_SIZE', 1024 * 1024 * 10)) # 10MB | |||
| READABLE_MAX_BINARY_SIZE = f'{MAX_BINARY_SIZE / 1024 / 1024:.2f}MB' | |||
| MAX_TEXT_SIZE = int(os.environ.get('HTTP_REQUEST_NODE_MAX_TEXT_SIZE', 1024 * 1024)) # 1MB | |||
| READABLE_MAX_TEXT_SIZE = f'{MAX_TEXT_SIZE / 1024 / 1024:.2f}MB' | |||
| MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE | |||
| READABLE_MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE | |||
| MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE | |||
| READABLE_MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE | |||
| class HttpExecutorResponse: | |||