dify/api/services/recommended_app_service.py

120 lines
4.8 KiB
Python

from typing import Any
from sqlalchemy import select
from sqlalchemy.orm import Session
from configs import dify_config
from enums.deployment_edition import DeploymentEdition
from models.model import AccountTrialAppRecord, App, TrialApp
from services.recommend_app.recommend_app_factory import RecommendAppRetrievalFactory
class RecommendedAppService:
"""Own recommended app retrieval and Cloud-only trial eligibility."""
@staticmethod
def is_trial_app_enabled() -> bool:
"""Return whether trial execution is enabled for this deployment."""
return dify_config.DEPLOYMENT_EDITION == DeploymentEdition.CLOUD and dify_config.ENABLE_TRIAL_APP
@classmethod
def get_app(cls, app_id: str, *, session: Session) -> App | None:
"""Return a normal app only when it belongs to the recommended catalog."""
mode = dify_config.HOSTED_FETCH_APP_TEMPLATES_MODE
retrieval_instance = RecommendAppRetrievalFactory.get_recommend_app_factory(mode)()
recommended_app_detail = retrieval_instance.get_recommend_app_detail(app_id, session=session)
if recommended_app_detail is None:
return None
return session.scalar(select(App).where(App.id == app_id, App.status == "normal").limit(1))
@classmethod
def get_recommended_apps_and_categories(cls, language: str, *, session: Session):
"""
Get recommended apps and categories.
:param language: language
:return:
"""
mode = dify_config.HOSTED_FETCH_APP_TEMPLATES_MODE
retrieval_instance = RecommendAppRetrievalFactory.get_recommend_app_factory(mode)()
result = retrieval_instance.get_recommended_apps_and_categories(language, session=session)
if not result.get("recommended_apps"):
result = (
RecommendAppRetrievalFactory.get_buildin_recommend_app_retrieval().fetch_recommended_apps_from_builtin(
"en-US"
)
)
apps = result["recommended_apps"]
trial_app_ids = (
cls._get_trial_app_ids(session, [app["app_id"] for app in apps]) if cls.is_trial_app_enabled() else set()
)
for app in apps:
app["can_trial"] = app["app_id"] in trial_app_ids
return result
@classmethod
def get_learn_dify_apps(cls, language: str, *, session: Session) -> dict[str, Any]:
"""
Get recommended apps marked for the Learn Dify section.
:param language: language
:return:
"""
mode = dify_config.HOSTED_FETCH_APP_TEMPLATES_MODE
retrieval_instance = RecommendAppRetrievalFactory.get_recommend_app_factory(mode)()
result = retrieval_instance.get_learn_dify_apps(language, session=session)
apps = result["recommended_apps"]
trial_app_ids = (
cls._get_trial_app_ids(session, [app["app_id"] for app in apps]) if cls.is_trial_app_enabled() else set()
)
for app in apps:
app["can_trial"] = app["app_id"] in trial_app_ids
return {"recommended_apps": apps}
@classmethod
def get_recommend_app_detail(cls, app_id: str, *, session: Session) -> dict[str, Any] | None:
"""
Get recommend app detail.
:param app_id: app id
:return:
"""
mode = dify_config.HOSTED_FETCH_APP_TEMPLATES_MODE
retrieval_instance = RecommendAppRetrievalFactory.get_recommend_app_factory(mode)()
result: dict[str, Any] | None = retrieval_instance.get_recommend_app_detail(app_id, session=session)
if result is None:
return None
result["can_trial"] = cls.is_trial_app_enabled() and cls._can_trial_app(session, result["id"])
return result
@classmethod
def add_trial_app_record(cls, app_id: str, account_id: str, *, session: Session):
"""
Add trial app record.
:param app_id: app id
:return:
"""
account_trial_app_record = session.scalar(
select(AccountTrialAppRecord)
.where(AccountTrialAppRecord.app_id == app_id, AccountTrialAppRecord.account_id == account_id)
.limit(1)
)
if account_trial_app_record:
account_trial_app_record.count += 1
session.commit()
else:
session.add(AccountTrialAppRecord(app_id=app_id, count=1, account_id=account_id))
session.commit()
@staticmethod
def _can_trial_app(session: Session, app_id: str) -> bool:
trial_app_model = session.scalar(select(TrialApp).where(TrialApp.app_id == app_id).limit(1))
return trial_app_model is not None
@staticmethod
def _get_trial_app_ids(session: Session, app_ids: list[str]) -> set[str]:
if not app_ids:
return set()
return set(session.scalars(select(TrialApp.app_id).where(TrialApp.app_id.in_(app_ids))).all())