Team Ai
Apppublic

Underground-Digital/Workflow-Engine

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app_service.py370 linesDownload Raw Back to services
1import json2import logging3from datetime import datetime, timezone4from typing import cast5 6from flask_login import current_user7from flask_sqlalchemy.pagination import Pagination8 9from configs import dify_config10from constants.model_template import default_app_templates11from core.agent.entities import AgentToolEntity12from core.app.features.rate_limiting import RateLimit13from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError14from core.model_manager import ModelManager15from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType16from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel17from core.tools.tool_manager import ToolManager18from core.tools.utils.configuration import ToolParameterConfigurationManager19from events.app_event import app_was_created20from extensions.ext_database import db21from models.account import Account22from models.model import App, AppMode, AppModelConfig23from models.tools import ApiToolProvider24from services.tag_service import TagService25from tasks.remove_app_and_related_data_task import remove_app_and_related_data_task26 27 28class AppService:29    def get_paginate_apps(self, tenant_id: str, args: dict) -> Pagination | None:30        """31        Get app list with pagination32        :param tenant_id: tenant id33        :param args: request args34        :return:35        """36        filters = [App.tenant_id == tenant_id, App.is_universal == False]37 38        if args["mode"] == "workflow":39            filters.append(App.mode.in_([AppMode.WORKFLOW.value, AppMode.COMPLETION.value]))40        elif args["mode"] == "chat":41            filters.append(App.mode.in_([AppMode.CHAT.value, AppMode.ADVANCED_CHAT.value]))42        elif args["mode"] == "agent-chat":43            filters.append(App.mode == AppMode.AGENT_CHAT.value)44        elif args["mode"] == "channel":45            filters.append(App.mode == AppMode.CHANNEL.value)46 47        if args.get("name"):48            name = args["name"][:30]49            filters.append(App.name.ilike(f"%{name}%"))50        if args.get("tag_ids"):51            target_ids = TagService.get_target_ids_by_tag_ids("app", tenant_id, args["tag_ids"])52            if target_ids:53                filters.append(App.id.in_(target_ids))54            else:55                return None56 57        app_models = db.paginate(58            db.select(App).where(*filters).order_by(App.created_at.desc()),59            page=args["page"],60            per_page=args["limit"],61            error_out=False,62        )63 64        return app_models65 66    def create_app(self, tenant_id: str, args: dict, account: Account) -> App:67        """68        Create app69        :param tenant_id: tenant id70        :param args: request args71        :param account: Account instance72        """73        app_mode = AppMode.value_of(args["mode"])74        app_template = default_app_templates[app_mode]75 76        # get model config77        default_model_config = app_template.get("model_config")78        default_model_config = default_model_config.copy() if default_model_config else None79        if default_model_config and "model" in default_model_config:80            # get model provider81            model_manager = ModelManager()82 83            # get default model instance84            try:85                model_instance = model_manager.get_default_model_instance(86                    tenant_id=account.current_tenant_id, model_type=ModelType.LLM87                )88            except (ProviderTokenNotInitError, LLMBadRequestError):89                model_instance = None90            except Exception as e:91                logging.exception(e)92                model_instance = None93 94            if model_instance:95                if (96                    model_instance.model == default_model_config["model"]["name"]97                    and model_instance.provider == default_model_config["model"]["provider"]98                ):99                    default_model_dict = default_model_config["model"]100                else:101                    llm_model = cast(LargeLanguageModel, model_instance.model_type_instance)102                    model_schema = llm_model.get_model_schema(model_instance.model, model_instance.credentials)103 104                    default_model_dict = {105                        "provider": model_instance.provider,106                        "name": model_instance.model,107                        "mode": model_schema.model_properties.get(ModelPropertyKey.MODE),108                        "completion_params": {},109                    }110            else:111                provider, model = model_manager.get_default_provider_model_name(112                    tenant_id=account.current_tenant_id, model_type=ModelType.LLM113                )114                default_model_config["model"]["provider"] = provider115                default_model_config["model"]["name"] = model116                default_model_dict = default_model_config["model"]117 118            default_model_config["model"] = json.dumps(default_model_dict)119 120        app = App(**app_template["app"])121        app.name = args["name"]122        app.description = args.get("description", "")123        app.mode = args["mode"]124        app.icon_type = args.get("icon_type", "emoji")125        app.icon = args["icon"]126        app.icon_background = args["icon_background"]127        app.tenant_id = tenant_id128        app.api_rph = args.get("api_rph", 0)129        app.api_rpm = args.get("api_rpm", 0)130        app.created_by = account.id131        app.updated_by = account.id132 133        db.session.add(app)134        db.session.flush()135 136        if default_model_config:137            app_model_config = AppModelConfig(**default_model_config)138            app_model_config.app_id = app.id139            app_model_config.created_by = account.id140            app_model_config.updated_by = account.id141            db.session.add(app_model_config)142            db.session.flush()143 144            app.app_model_config_id = app_model_config.id145 146        db.session.commit()147 148        app_was_created.send(app, account=account)149 150        return app151 152    def get_app(self, app: App) -> App:153        """154        Get App155        """156        # get original app model config157        if app.mode == AppMode.AGENT_CHAT.value or app.is_agent:158            model_config: AppModelConfig = app.app_model_config159            agent_mode = model_config.agent_mode_dict160            # decrypt agent tool parameters if it's secret-input161            for tool in agent_mode.get("tools") or []:162                if not isinstance(tool, dict) or len(tool.keys()) <= 3:163                    continue164                agent_tool_entity = AgentToolEntity(**tool)165                # get tool166                try:167                    tool_runtime = ToolManager.get_agent_tool_runtime(168                        tenant_id=current_user.current_tenant_id,169                        app_id=app.id,170                        agent_tool=agent_tool_entity,171                    )172                    manager = ToolParameterConfigurationManager(173                        tenant_id=current_user.current_tenant_id,174                        tool_runtime=tool_runtime,175                        provider_name=agent_tool_entity.provider_id,176                        provider_type=agent_tool_entity.provider_type,177                        identity_id=f"AGENT.{app.id}",178                    )179 180                    # get decrypted parameters181                    if agent_tool_entity.tool_parameters:182                        parameters = manager.decrypt_tool_parameters(agent_tool_entity.tool_parameters or {})183                        masked_parameter = manager.mask_tool_parameters(parameters or {})184                    else:185                        masked_parameter = {}186 187                    # override tool parameters188                    tool["tool_parameters"] = masked_parameter189                except Exception as e:190                    pass191 192            # override agent mode193            model_config.agent_mode = json.dumps(agent_mode)194 195            class ModifiedApp(App):196                """197                Modified App class198                """199 200                def __init__(self, app):201                    self.__dict__.update(app.__dict__)202 203                @property204                def app_model_config(self):205                    return model_config206 207            app = ModifiedApp(app)208 209        return app210 211    def update_app(self, app: App, args: dict) -> App:212        """213        Update app214        :param app: App instance215        :param args: request args216        :return: App instance217        """218        app.name = args.get("name")219        app.description = args.get("description", "")220        app.max_active_requests = args.get("max_active_requests")221        app.icon_type = args.get("icon_type", "emoji")222        app.icon = args.get("icon")223        app.icon_background = args.get("icon_background")224        app.use_icon_as_answer_icon = args.get("use_icon_as_answer_icon", False)225        app.updated_by = current_user.id226        app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)227        db.session.commit()228 229        if app.max_active_requests is not None:230            rate_limit = RateLimit(app.id, app.max_active_requests)231            rate_limit.flush_cache(use_local_value=True)232        return app233 234    def update_app_name(self, app: App, name: str) -> App:235        """236        Update app name237        :param app: App instance238        :param name: new name239        :return: App instance240        """241        app.name = name242        app.updated_by = current_user.id243        app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)244        db.session.commit()245 246        return app247 248    def update_app_icon(self, app: App, icon: str, icon_background: str) -> App:249        """250        Update app icon251        :param app: App instance252        :param icon: new icon253        :param icon_background: new icon_background254        :return: App instance255        """256        app.icon = icon257        app.icon_background = icon_background258        app.updated_by = current_user.id259        app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)260        db.session.commit()261 262        return app263 264    def update_app_site_status(self, app: App, enable_site: bool) -> App:265        """266        Update app site status267        :param app: App instance268        :param enable_site: enable site status269        :return: App instance270        """271        if enable_site == app.enable_site:272            return app273 274        app.enable_site = enable_site275        app.updated_by = current_user.id276        app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)277        db.session.commit()278 279        return app280 281    def update_app_api_status(self, app: App, enable_api: bool) -> App:282        """283        Update app api status284        :param app: App instance285        :param enable_api: enable api status286        :return: App instance287        """288        if enable_api == app.enable_api:289            return app290 291        app.enable_api = enable_api292        app.updated_by = current_user.id293        app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)294        db.session.commit()295 296        return app297 298    def delete_app(self, app: App) -> None:299        """300        Delete app301        :param app: App instance302        """303        db.session.delete(app)304        db.session.commit()305 306        # Trigger asynchronous deletion of app and related data307        remove_app_and_related_data_task.delay(tenant_id=app.tenant_id, app_id=app.id)308 309    def get_app_meta(self, app_model: App) -> dict:310        """311        Get app meta info312        :param app_model: app model313        :return:314        """315        app_mode = AppMode.value_of(app_model.mode)316 317        meta = {"tool_icons": {}}318 319        if app_mode in {AppMode.ADVANCED_CHAT, AppMode.WORKFLOW}:320            workflow = app_model.workflow321            if workflow is None:322                return meta323 324            graph = workflow.graph_dict325            nodes = graph.get("nodes", [])326            tools = []327            for node in nodes:328                if node.get("data", {}).get("type") == "tool":329                    node_data = node.get("data", {})330                    tools.append(331                        {332                            "provider_type": node_data.get("provider_type"),333                            "provider_id": node_data.get("provider_id"),334                            "tool_name": node_data.get("tool_name"),335                            "tool_parameters": {},336                        }337                    )338        else:339            app_model_config: AppModelConfig = app_model.app_model_config340 341            if not app_model_config:342                return meta343 344            agent_config = app_model_config.agent_mode_dict or {}345 346            # get all tools347            tools = agent_config.get("tools", [])348 349        url_prefix = dify_config.CONSOLE_API_URL + "/console/api/workspaces/current/tool-provider/builtin/"350 351        for tool in tools:352            keys = list(tool.keys())353            if len(keys) >= 4:354                # current tool standard355                provider_type = tool.get("provider_type")356                provider_id = tool.get("provider_id")357                tool_name = tool.get("tool_name")358                if provider_type == "builtin":359                    meta["tool_icons"][tool_name] = url_prefix + provider_id + "/icon"360                elif provider_type == "api":361                    try:362                        provider: ApiToolProvider = (363                            db.session.query(ApiToolProvider).filter(ApiToolProvider.id == provider_id).first()364                        )365                        meta["tool_icons"][tool_name] = json.loads(provider.icon)366                    except:367                        meta["tool_icons"][tool_name] = {"background": "#252525", "content": "\ud83d\ude01"}368 369        return meta370