Signed-off-by: -LAN- <laipz8200@outlook.com> Co-authored-by: -LAN- <laipz8200@outlook.com>tags/0.13.0
| cp .env.example .env | cp .env.example .env | ||||
| - name: Run DB Migration | - name: Run DB Migration | ||||
| env: | |||||
| DEBUG: true | |||||
| run: | | run: | | ||||
| cd api | cd api | ||||
| poetry run python -m flask upgrade-db | poetry run python -m flask upgrade-db |
| import os | |||||
| import sys | |||||
| python_version = sys.version_info | |||||
| if not ((3, 11) <= python_version < (3, 13)): | |||||
| print(f"Python 3.11 or 3.12 is required, current version is {python_version.major}.{python_version.minor}") | |||||
| raise SystemExit(1) | |||||
| from configs import dify_config | |||||
| if not dify_config.DEBUG: | |||||
| from gevent import monkey | |||||
| monkey.patch_all() | |||||
| import grpc.experimental.gevent | |||||
| grpc.experimental.gevent.init_gevent() | |||||
| import json | |||||
| import threading | |||||
| import time | |||||
| import warnings | |||||
| from flask import Response | |||||
| from app_factory import create_app | from app_factory import create_app | ||||
| from libs import threadings_utils, version_utils | |||||
| # DO NOT REMOVE BELOW | |||||
| from events import event_handlers # noqa: F401 | |||||
| from extensions.ext_database import db | |||||
| # TODO: Find a way to avoid importing models here | |||||
| from models import account, dataset, model, source, task, tool, tools, web # noqa: F401 | |||||
| # DO NOT REMOVE ABOVE | |||||
| warnings.simplefilter("ignore", ResourceWarning) | |||||
| os.environ["TZ"] = "UTC" | |||||
| # windows platform not support tzset | |||||
| if hasattr(time, "tzset"): | |||||
| time.tzset() | |||||
| # preparation before creating app | |||||
| version_utils.check_supported_python_version() | |||||
| threadings_utils.apply_gevent_threading_patch() | |||||
| # create app | # create app | ||||
| app = create_app() | app = create_app() | ||||
| celery = app.extensions["celery"] | celery = app.extensions["celery"] | ||||
| if dify_config.TESTING: | |||||
| print("App is running in TESTING mode") | |||||
| @app.after_request | |||||
| def after_request(response): | |||||
| """Add Version headers to the response.""" | |||||
| response.headers.add("X-Version", dify_config.CURRENT_VERSION) | |||||
| response.headers.add("X-Env", dify_config.DEPLOY_ENV) | |||||
| return response | |||||
| @app.route("/health") | |||||
| def health(): | |||||
| return Response( | |||||
| json.dumps({"pid": os.getpid(), "status": "ok", "version": dify_config.CURRENT_VERSION}), | |||||
| status=200, | |||||
| content_type="application/json", | |||||
| ) | |||||
| @app.route("/threads") | |||||
| def threads(): | |||||
| num_threads = threading.active_count() | |||||
| threads = threading.enumerate() | |||||
| thread_list = [] | |||||
| for thread in threads: | |||||
| thread_name = thread.name | |||||
| thread_id = thread.ident | |||||
| is_alive = thread.is_alive() | |||||
| thread_list.append( | |||||
| { | |||||
| "name": thread_name, | |||||
| "id": thread_id, | |||||
| "is_alive": is_alive, | |||||
| } | |||||
| ) | |||||
| return { | |||||
| "pid": os.getpid(), | |||||
| "thread_num": num_threads, | |||||
| "threads": thread_list, | |||||
| } | |||||
| @app.route("/db-pool-stat") | |||||
| def pool_stat(): | |||||
| engine = db.engine | |||||
| return { | |||||
| "pid": os.getpid(), | |||||
| "pool_size": engine.pool.size(), | |||||
| "checked_in_connections": engine.pool.checkedin(), | |||||
| "checked_out_connections": engine.pool.checkedout(), | |||||
| "overflow_connections": engine.pool.overflow(), | |||||
| "connection_timeout": engine.pool.timeout(), | |||||
| "recycle_time": db.engine.pool._recycle, | |||||
| } | |||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||
| app.run(host="0.0.0.0", port=5001) | app.run(host="0.0.0.0", port=5001) |
| import logging | |||||
| import os | import os | ||||
| import time | |||||
| from configs import dify_config | from configs import dify_config | ||||
| if not dify_config.DEBUG: | |||||
| from gevent import monkey | |||||
| monkey.patch_all() | |||||
| import grpc.experimental.gevent | |||||
| grpc.experimental.gevent.init_gevent() | |||||
| import json | |||||
| from flask import Flask, Response, request | |||||
| from flask_cors import CORS | |||||
| from flask_login import user_loaded_from_request, user_logged_in | |||||
| from werkzeug.exceptions import Unauthorized | |||||
| import contexts | |||||
| from commands import register_commands | |||||
| from configs import dify_config | |||||
| from extensions import ( | |||||
| ext_celery, | |||||
| ext_code_based_extension, | |||||
| ext_compress, | |||||
| ext_database, | |||||
| ext_hosting_provider, | |||||
| ext_logging, | |||||
| ext_login, | |||||
| ext_mail, | |||||
| ext_migrate, | |||||
| ext_proxy_fix, | |||||
| ext_redis, | |||||
| ext_sentry, | |||||
| ext_storage, | |||||
| ) | |||||
| from extensions.ext_database import db | |||||
| from extensions.ext_login import login_manager | |||||
| from libs.passport import PassportService | |||||
| from services.account_service import AccountService | |||||
| class DifyApp(Flask): | |||||
| pass | |||||
| from dify_app import DifyApp | |||||
| # ---------------------------- | # ---------------------------- | ||||
| # Application Factory Function | # Application Factory Function | ||||
| # ---------------------------- | # ---------------------------- | ||||
| def create_flask_app_with_configs() -> Flask: | |||||
| def create_flask_app_with_configs() -> DifyApp: | |||||
| """ | """ | ||||
| create a raw flask app | create a raw flask app | ||||
| with configs loaded from .env file | with configs loaded from .env file | ||||
| return dify_app | return dify_app | ||||
| def create_app() -> Flask: | |||||
| def create_app() -> DifyApp: | |||||
| start_time = time.perf_counter() | |||||
| app = create_flask_app_with_configs() | app = create_flask_app_with_configs() | ||||
| app.secret_key = dify_config.SECRET_KEY | |||||
| initialize_extensions(app) | initialize_extensions(app) | ||||
| register_blueprints(app) | |||||
| register_commands(app) | |||||
| end_time = time.perf_counter() | |||||
| if dify_config.DEBUG: | |||||
| logging.info(f"Finished create_app ({round((end_time - start_time) * 1000, 2)} ms)") | |||||
| return app | return app | ||||
| def initialize_extensions(app): | |||||
| # Since the application instance is now created, pass it to each Flask | |||||
| # extension instance to bind it to the Flask application instance (app) | |||||
| ext_logging.init_app(app) | |||||
| ext_compress.init_app(app) | |||||
| ext_code_based_extension.init() | |||||
| ext_database.init_app(app) | |||||
| ext_migrate.init(app, db) | |||||
| ext_redis.init_app(app) | |||||
| ext_storage.init_app(app) | |||||
| ext_celery.init_app(app) | |||||
| ext_login.init_app(app) | |||||
| ext_mail.init_app(app) | |||||
| ext_hosting_provider.init_app(app) | |||||
| ext_sentry.init_app(app) | |||||
| ext_proxy_fix.init_app(app) | |||||
| # Flask-Login configuration | |||||
| @login_manager.request_loader | |||||
| def load_user_from_request(request_from_flask_login): | |||||
| """Load user based on the request.""" | |||||
| if request.blueprint not in {"console", "inner_api"}: | |||||
| return None | |||||
| # Check if the user_id contains a dot, indicating the old format | |||||
| auth_header = request.headers.get("Authorization", "") | |||||
| if not auth_header: | |||||
| auth_token = request.args.get("_token") | |||||
| if not auth_token: | |||||
| raise Unauthorized("Invalid Authorization token.") | |||||
| else: | |||||
| if " " not in auth_header: | |||||
| raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.") | |||||
| auth_scheme, auth_token = auth_header.split(None, 1) | |||||
| auth_scheme = auth_scheme.lower() | |||||
| if auth_scheme != "bearer": | |||||
| raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.") | |||||
| decoded = PassportService().verify(auth_token) | |||||
| user_id = decoded.get("user_id") | |||||
| logged_in_account = AccountService.load_logged_in_account(account_id=user_id) | |||||
| return logged_in_account | |||||
| @user_logged_in.connect | |||||
| @user_loaded_from_request.connect | |||||
| def on_user_logged_in(_sender, user): | |||||
| """Called when a user logged in.""" | |||||
| if user: | |||||
| contexts.tenant_id.set(user.current_tenant_id) | |||||
| @login_manager.unauthorized_handler | |||||
| def unauthorized_handler(): | |||||
| """Handle unauthorized requests.""" | |||||
| return Response( | |||||
| json.dumps({"code": "unauthorized", "message": "Unauthorized."}), | |||||
| status=401, | |||||
| content_type="application/json", | |||||
| ) | |||||
| # register blueprint routers | |||||
| def register_blueprints(app): | |||||
| from controllers.console import bp as console_app_bp | |||||
| from controllers.files import bp as files_bp | |||||
| from controllers.inner_api import bp as inner_api_bp | |||||
| from controllers.service_api import bp as service_api_bp | |||||
| from controllers.web import bp as web_bp | |||||
| CORS( | |||||
| service_api_bp, | |||||
| allow_headers=["Content-Type", "Authorization", "X-App-Code"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| def initialize_extensions(app: DifyApp): | |||||
| from extensions import ( | |||||
| ext_app_metrics, | |||||
| ext_blueprints, | |||||
| ext_celery, | |||||
| ext_code_based_extension, | |||||
| ext_commands, | |||||
| ext_compress, | |||||
| ext_database, | |||||
| ext_hosting_provider, | |||||
| ext_import_modules, | |||||
| ext_logging, | |||||
| ext_login, | |||||
| ext_mail, | |||||
| ext_migrate, | |||||
| ext_proxy_fix, | |||||
| ext_redis, | |||||
| ext_sentry, | |||||
| ext_set_secretkey, | |||||
| ext_storage, | |||||
| ext_timezone, | |||||
| ext_warnings, | |||||
| ) | ) | ||||
| app.register_blueprint(service_api_bp) | |||||
| CORS( | |||||
| web_bp, | |||||
| resources={r"/*": {"origins": dify_config.WEB_API_CORS_ALLOW_ORIGINS}}, | |||||
| supports_credentials=True, | |||||
| allow_headers=["Content-Type", "Authorization", "X-App-Code"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| expose_headers=["X-Version", "X-Env"], | |||||
| ) | |||||
| app.register_blueprint(web_bp) | |||||
| CORS( | |||||
| console_app_bp, | |||||
| resources={r"/*": {"origins": dify_config.CONSOLE_CORS_ALLOW_ORIGINS}}, | |||||
| supports_credentials=True, | |||||
| allow_headers=["Content-Type", "Authorization"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| expose_headers=["X-Version", "X-Env"], | |||||
| ) | |||||
| app.register_blueprint(console_app_bp) | |||||
| CORS(files_bp, allow_headers=["Content-Type"], methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"]) | |||||
| app.register_blueprint(files_bp) | |||||
| app.register_blueprint(inner_api_bp) | |||||
| extensions = [ | |||||
| ext_timezone, | |||||
| ext_logging, | |||||
| ext_warnings, | |||||
| ext_import_modules, | |||||
| ext_set_secretkey, | |||||
| ext_compress, | |||||
| ext_code_based_extension, | |||||
| ext_database, | |||||
| ext_app_metrics, | |||||
| ext_migrate, | |||||
| ext_redis, | |||||
| ext_storage, | |||||
| ext_celery, | |||||
| ext_login, | |||||
| ext_mail, | |||||
| ext_hosting_provider, | |||||
| ext_sentry, | |||||
| ext_proxy_fix, | |||||
| ext_blueprints, | |||||
| ext_commands, | |||||
| ] | |||||
| for ext in extensions: | |||||
| short_name = ext.__name__.split(".")[-1] | |||||
| is_enabled = ext.is_enabled() if hasattr(ext, "is_enabled") else True | |||||
| if not is_enabled: | |||||
| if dify_config.DEBUG: | |||||
| logging.info(f"Skipped {short_name}") | |||||
| continue | |||||
| start_time = time.perf_counter() | |||||
| ext.init_app(app) | |||||
| end_time = time.perf_counter() | |||||
| if dify_config.DEBUG: | |||||
| logging.info(f"Loaded {short_name} ({round((end_time - start_time) * 1000, 2)} ms)") |
| break | break | ||||
| click.echo(click.style("Fix for missing app-related sites completed successfully!", fg="green")) | click.echo(click.style("Fix for missing app-related sites completed successfully!", fg="green")) | ||||
| def register_commands(app): | |||||
| app.cli.add_command(reset_password) | |||||
| app.cli.add_command(reset_email) | |||||
| app.cli.add_command(reset_encrypt_key_pair) | |||||
| app.cli.add_command(vdb_migrate) | |||||
| app.cli.add_command(convert_to_agent_apps) | |||||
| app.cli.add_command(add_qdrant_doc_id_index) | |||||
| app.cli.add_command(create_tenant) | |||||
| app.cli.add_command(upgrade_db) | |||||
| app.cli.add_command(fix_app_site_missing) |
| default=False, | default=False, | ||||
| ) | ) | ||||
| TESTING: bool = Field( | |||||
| description="Enable testing mode for running automated tests", | |||||
| default=False, | |||||
| ) | |||||
| EDITION: str = Field( | EDITION: str = Field( | ||||
| description="Deployment edition of the application (e.g., 'SELF_HOSTED', 'CLOUD')", | description="Deployment edition of the application (e.g., 'SELF_HOSTED', 'CLOUD')", | ||||
| default="SELF_HOSTED", | default="SELF_HOSTED", |
| from flask import Flask | |||||
| class DifyApp(Flask): | |||||
| pass |
| import json | |||||
| import os | |||||
| import threading | |||||
| from flask import Response | |||||
| from configs import dify_config | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| @app.after_request | |||||
| def after_request(response): | |||||
| """Add Version headers to the response.""" | |||||
| response.headers.add("X-Version", dify_config.CURRENT_VERSION) | |||||
| response.headers.add("X-Env", dify_config.DEPLOY_ENV) | |||||
| return response | |||||
| @app.route("/health") | |||||
| def health(): | |||||
| return Response( | |||||
| json.dumps({"pid": os.getpid(), "status": "ok", "version": dify_config.CURRENT_VERSION}), | |||||
| status=200, | |||||
| content_type="application/json", | |||||
| ) | |||||
| @app.route("/threads") | |||||
| def threads(): | |||||
| num_threads = threading.active_count() | |||||
| threads = threading.enumerate() | |||||
| thread_list = [] | |||||
| for thread in threads: | |||||
| thread_name = thread.name | |||||
| thread_id = thread.ident | |||||
| is_alive = thread.is_alive() | |||||
| thread_list.append( | |||||
| { | |||||
| "name": thread_name, | |||||
| "id": thread_id, | |||||
| "is_alive": is_alive, | |||||
| } | |||||
| ) | |||||
| return { | |||||
| "pid": os.getpid(), | |||||
| "thread_num": num_threads, | |||||
| "threads": thread_list, | |||||
| } | |||||
| @app.route("/db-pool-stat") | |||||
| def pool_stat(): | |||||
| from extensions.ext_database import db | |||||
| engine = db.engine | |||||
| return { | |||||
| "pid": os.getpid(), | |||||
| "pool_size": engine.pool.size(), | |||||
| "checked_in_connections": engine.pool.checkedin(), | |||||
| "checked_out_connections": engine.pool.checkedout(), | |||||
| "overflow_connections": engine.pool.overflow(), | |||||
| "connection_timeout": engine.pool.timeout(), | |||||
| "recycle_time": db.engine.pool._recycle, | |||||
| } |
| from configs import dify_config | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| # register blueprint routers | |||||
| from flask_cors import CORS | |||||
| from controllers.console import bp as console_app_bp | |||||
| from controllers.files import bp as files_bp | |||||
| from controllers.inner_api import bp as inner_api_bp | |||||
| from controllers.service_api import bp as service_api_bp | |||||
| from controllers.web import bp as web_bp | |||||
| CORS( | |||||
| service_api_bp, | |||||
| allow_headers=["Content-Type", "Authorization", "X-App-Code"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| ) | |||||
| app.register_blueprint(service_api_bp) | |||||
| CORS( | |||||
| web_bp, | |||||
| resources={r"/*": {"origins": dify_config.WEB_API_CORS_ALLOW_ORIGINS}}, | |||||
| supports_credentials=True, | |||||
| allow_headers=["Content-Type", "Authorization", "X-App-Code"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| expose_headers=["X-Version", "X-Env"], | |||||
| ) | |||||
| app.register_blueprint(web_bp) | |||||
| CORS( | |||||
| console_app_bp, | |||||
| resources={r"/*": {"origins": dify_config.CONSOLE_CORS_ALLOW_ORIGINS}}, | |||||
| supports_credentials=True, | |||||
| allow_headers=["Content-Type", "Authorization"], | |||||
| methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"], | |||||
| expose_headers=["X-Version", "X-Env"], | |||||
| ) | |||||
| app.register_blueprint(console_app_bp) | |||||
| CORS(files_bp, allow_headers=["Content-Type"], methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"]) | |||||
| app.register_blueprint(files_bp) | |||||
| app.register_blueprint(inner_api_bp) |
| import pytz | import pytz | ||||
| from celery import Celery, Task | from celery import Celery, Task | ||||
| from celery.schedules import crontab | from celery.schedules import crontab | ||||
| from flask import Flask | |||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| def init_app(app: Flask) -> Celery: | |||||
| def init_app(app: DifyApp) -> Celery: | |||||
| class FlaskTask(Task): | class FlaskTask(Task): | ||||
| def __call__(self, *args: object, **kwargs: object) -> object: | def __call__(self, *args: object, **kwargs: object) -> object: | ||||
| with app.app_context(): | with app.app_context(): |
| from core.extension.extension import Extension | from core.extension.extension import Extension | ||||
| from dify_app import DifyApp | |||||
| def init(): | |||||
| def init_app(app: DifyApp): | |||||
| code_based_extension.init() | code_based_extension.init() | ||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| from commands import ( | |||||
| add_qdrant_doc_id_index, | |||||
| convert_to_agent_apps, | |||||
| create_tenant, | |||||
| fix_app_site_missing, | |||||
| reset_email, | |||||
| reset_encrypt_key_pair, | |||||
| reset_password, | |||||
| upgrade_db, | |||||
| vdb_migrate, | |||||
| ) | |||||
| cmds_to_register = [ | |||||
| reset_password, | |||||
| reset_email, | |||||
| reset_encrypt_key_pair, | |||||
| vdb_migrate, | |||||
| convert_to_agent_apps, | |||||
| add_qdrant_doc_id_index, | |||||
| create_tenant, | |||||
| upgrade_db, | |||||
| fix_app_site_missing, | |||||
| ] | |||||
| for cmd in cmds_to_register: | |||||
| app.cli.add_command(cmd) |
| from flask import Flask | |||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| def is_enabled() -> bool: | |||||
| return dify_config.API_COMPRESSION_ENABLED | |||||
| def init_app(app: Flask): | |||||
| if dify_config.API_COMPRESSION_ENABLED: | |||||
| from flask_compress import Compress | |||||
| def init_app(app: DifyApp): | |||||
| from flask_compress import Compress | |||||
| compress = Compress() | |||||
| compress.init_app(app) | |||||
| compress = Compress() | |||||
| compress.init_app(app) |
| from flask_sqlalchemy import SQLAlchemy | from flask_sqlalchemy import SQLAlchemy | ||||
| from sqlalchemy import MetaData | from sqlalchemy import MetaData | ||||
| from dify_app import DifyApp | |||||
| POSTGRES_INDEXES_NAMING_CONVENTION = { | POSTGRES_INDEXES_NAMING_CONVENTION = { | ||||
| "ix": "%(column_0_label)s_idx", | "ix": "%(column_0_label)s_idx", | ||||
| "uq": "%(table_name)s_%(column_0_name)s_key", | "uq": "%(table_name)s_%(column_0_name)s_key", | ||||
| db = SQLAlchemy(metadata=metadata) | db = SQLAlchemy(metadata=metadata) | ||||
| def init_app(app): | |||||
| def init_app(app: DifyApp): | |||||
| db.init_app(app) | db.init_app(app) |
| from flask import Flask | |||||
| from core.hosting_configuration import HostingConfiguration | from core.hosting_configuration import HostingConfiguration | ||||
| hosting_configuration = HostingConfiguration() | hosting_configuration = HostingConfiguration() | ||||
| def init_app(app: Flask): | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| hosting_configuration.init_app(app) | hosting_configuration.init_app(app) |
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| from events import event_handlers # noqa: F401 | |||||
| from models import account, dataset, model, source, task, tool, tools, web # noqa: F401 |
| import sys | import sys | ||||
| from logging.handlers import RotatingFileHandler | from logging.handlers import RotatingFileHandler | ||||
| from flask import Flask | |||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| def init_app(app: Flask): | |||||
| def init_app(app: DifyApp): | |||||
| log_handlers = [] | log_handlers = [] | ||||
| log_file = dify_config.LOG_FILE | log_file = dify_config.LOG_FILE | ||||
| if log_file: | if log_file: |
| import json | |||||
| import flask_login | import flask_login | ||||
| from flask import Response, request | |||||
| from flask_login import user_loaded_from_request, user_logged_in | |||||
| from werkzeug.exceptions import Unauthorized | |||||
| import contexts | |||||
| from dify_app import DifyApp | |||||
| from libs.passport import PassportService | |||||
| from services.account_service import AccountService | |||||
| login_manager = flask_login.LoginManager() | login_manager = flask_login.LoginManager() | ||||
| def init_app(app): | |||||
| # Flask-Login configuration | |||||
| @login_manager.request_loader | |||||
| def load_user_from_request(request_from_flask_login): | |||||
| """Load user based on the request.""" | |||||
| if request.blueprint not in {"console", "inner_api"}: | |||||
| return None | |||||
| # Check if the user_id contains a dot, indicating the old format | |||||
| auth_header = request.headers.get("Authorization", "") | |||||
| if not auth_header: | |||||
| auth_token = request.args.get("_token") | |||||
| if not auth_token: | |||||
| raise Unauthorized("Invalid Authorization token.") | |||||
| else: | |||||
| if " " not in auth_header: | |||||
| raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.") | |||||
| auth_scheme, auth_token = auth_header.split(None, 1) | |||||
| auth_scheme = auth_scheme.lower() | |||||
| if auth_scheme != "bearer": | |||||
| raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.") | |||||
| decoded = PassportService().verify(auth_token) | |||||
| user_id = decoded.get("user_id") | |||||
| logged_in_account = AccountService.load_logged_in_account(account_id=user_id) | |||||
| return logged_in_account | |||||
| @user_logged_in.connect | |||||
| @user_loaded_from_request.connect | |||||
| def on_user_logged_in(_sender, user): | |||||
| """Called when a user logged in.""" | |||||
| if user: | |||||
| contexts.tenant_id.set(user.current_tenant_id) | |||||
| @login_manager.unauthorized_handler | |||||
| def unauthorized_handler(): | |||||
| """Handle unauthorized requests.""" | |||||
| return Response( | |||||
| json.dumps({"code": "unauthorized", "message": "Unauthorized."}), | |||||
| status=401, | |||||
| content_type="application/json", | |||||
| ) | |||||
| def init_app(app: DifyApp): | |||||
| login_manager.init_app(app) | login_manager.init_app(app) |
| import logging | import logging | ||||
| from typing import Optional | from typing import Optional | ||||
| import resend | |||||
| from flask import Flask | from flask import Flask | ||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| class Mail: | class Mail: | ||||
| match mail_type: | match mail_type: | ||||
| case "resend": | case "resend": | ||||
| import resend | |||||
| api_key = dify_config.RESEND_API_KEY | api_key = dify_config.RESEND_API_KEY | ||||
| if not api_key: | if not api_key: | ||||
| raise ValueError("RESEND_API_KEY is not set") | raise ValueError("RESEND_API_KEY is not set") | ||||
| ) | ) | ||||
| def init_app(app: Flask): | |||||
| def is_enabled() -> bool: | |||||
| return dify_config.MAIL_TYPE is not None and dify_config.MAIL_TYPE != "" | |||||
| def init_app(app: DifyApp): | |||||
| mail.init_app(app) | mail.init_app(app) | ||||
| import flask_migrate | |||||
| from dify_app import DifyApp | |||||
| def init(app, db): | |||||
| def init_app(app: DifyApp): | |||||
| import flask_migrate | |||||
| from extensions.ext_database import db | |||||
| flask_migrate.Migrate(app, db) | flask_migrate.Migrate(app, db) |
| from flask import Flask | |||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| def init_app(app: Flask): | |||||
| def init_app(app: DifyApp): | |||||
| if dify_config.RESPECT_XFORWARD_HEADERS_ENABLED: | if dify_config.RESPECT_XFORWARD_HEADERS_ENABLED: | ||||
| from werkzeug.middleware.proxy_fix import ProxyFix | from werkzeug.middleware.proxy_fix import ProxyFix | ||||
| from redis.sentinel import Sentinel | from redis.sentinel import Sentinel | ||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| class RedisClientWrapper: | class RedisClientWrapper: | ||||
| redis_client = RedisClientWrapper() | redis_client = RedisClientWrapper() | ||||
| def init_app(app): | |||||
| def init_app(app: DifyApp): | |||||
| global redis_client | global redis_client | ||||
| connection_class = Connection | connection_class = Connection | ||||
| if dify_config.REDIS_USE_SSL: | if dify_config.REDIS_USE_SSL: |
| import openai | |||||
| import sentry_sdk | |||||
| from langfuse import parse_error | |||||
| from sentry_sdk.integrations.celery import CeleryIntegration | |||||
| from sentry_sdk.integrations.flask import FlaskIntegration | |||||
| from werkzeug.exceptions import HTTPException | |||||
| from configs import dify_config | from configs import dify_config | ||||
| from core.model_runtime.errors.invoke import InvokeRateLimitError | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| if dify_config.SENTRY_DSN: | |||||
| import openai | |||||
| import sentry_sdk | |||||
| from langfuse import parse_error | |||||
| from sentry_sdk.integrations.celery import CeleryIntegration | |||||
| from sentry_sdk.integrations.flask import FlaskIntegration | |||||
| from werkzeug.exceptions import HTTPException | |||||
| def before_send(event, hint): | |||||
| if "exc_info" in hint: | |||||
| exc_type, exc_value, tb = hint["exc_info"] | |||||
| if parse_error.defaultErrorResponse in str(exc_value): | |||||
| return None | |||||
| from core.model_runtime.errors.invoke import InvokeRateLimitError | |||||
| return event | |||||
| def before_send(event, hint): | |||||
| if "exc_info" in hint: | |||||
| exc_type, exc_value, tb = hint["exc_info"] | |||||
| if parse_error.defaultErrorResponse in str(exc_value): | |||||
| return None | |||||
| return event | |||||
| def init_app(app): | |||||
| if dify_config.SENTRY_DSN: | |||||
| sentry_sdk.init( | sentry_sdk.init( | ||||
| dsn=dify_config.SENTRY_DSN, | dsn=dify_config.SENTRY_DSN, | ||||
| integrations=[FlaskIntegration(), CeleryIntegration()], | integrations=[FlaskIntegration(), CeleryIntegration()], |
| from configs import dify_config | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| app.secret_key = dify_config.SECRET_KEY |
| from flask import Flask | from flask import Flask | ||||
| from configs import dify_config | from configs import dify_config | ||||
| from dify_app import DifyApp | |||||
| from extensions.storage.base_storage import BaseStorage | from extensions.storage.base_storage import BaseStorage | ||||
| from extensions.storage.storage_type import StorageType | from extensions.storage.storage_type import StorageType | ||||
| storage = Storage() | storage = Storage() | ||||
| def init_app(app: Flask): | |||||
| def init_app(app: DifyApp): | |||||
| storage.init_app(app) | storage.init_app(app) |
| import os | |||||
| import time | |||||
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| os.environ["TZ"] = "UTC" | |||||
| # windows platform not support tzset | |||||
| if hasattr(time, "tzset"): | |||||
| time.tzset() |
| from dify_app import DifyApp | |||||
| def init_app(app: DifyApp): | |||||
| import warnings | |||||
| warnings.simplefilter("ignore", ResourceWarning) |
| from configs import dify_config | |||||
| def apply_gevent_threading_patch(): | |||||
| """ | |||||
| Run threading patch by gevent | |||||
| to make standard library threading compatible. | |||||
| Patching should be done as early as possible in the lifecycle of the program. | |||||
| :return: | |||||
| """ | |||||
| if not dify_config.DEBUG: | |||||
| from gevent import monkey | |||||
| from grpc.experimental import gevent as grpc_gevent | |||||
| # gevent | |||||
| monkey.patch_all() | |||||
| # grpc gevent | |||||
| grpc_gevent.init_gevent() |
| import sys | |||||
| def check_supported_python_version(): | |||||
| python_version = sys.version_info | |||||
| if not ((3, 11) <= python_version < (3, 13)): | |||||
| print( | |||||
| "Aborted to launch the service " | |||||
| f" with unsupported Python version {python_version.major}.{python_version.minor}." | |||||
| " Please ensure Python 3.11 or 3.12." | |||||
| ) | |||||
| raise SystemExit(1) |
| assert config["EDITION"] == "SELF_HOSTED" | assert config["EDITION"] == "SELF_HOSTED" | ||||
| assert config["API_COMPRESSION_ENABLED"] is False | assert config["API_COMPRESSION_ENABLED"] is False | ||||
| assert config["SENTRY_TRACES_SAMPLE_RATE"] == 1.0 | assert config["SENTRY_TRACES_SAMPLE_RATE"] == 1.0 | ||||
| assert config["TESTING"] == False | |||||
| # value from env file | # value from env file | ||||
| assert config["CONSOLE_API_URL"] == "https://example.com" | assert config["CONSOLE_API_URL"] == "https://example.com" |
| PROJECT_DIR = os.path.abspath(os.path.join(ABS_PATH, os.pardir, os.pardir)) | PROJECT_DIR = os.path.abspath(os.path.join(ABS_PATH, os.pardir, os.pardir)) | ||||
| CACHED_APP = Flask(__name__) | CACHED_APP = Flask(__name__) | ||||
| CACHED_APP.config.update({"TESTING": True}) | |||||
| @pytest.fixture | @pytest.fixture |