Files
dify/api/extensions/application_services/installed_app.py

80 lines
3.7 KiB
Python

"""Composition of Installed App use cases."""
from dataclasses import dataclass
from flask import current_app
from sqlalchemy.orm import Session, sessionmaker
from repositories.installed_app_conversation_repository import SQLAlchemyInstalledAppConversationRepository
from repositories.installed_app_message_repository import SQLAlchemyInstalledAppMessageRepository
from repositories.installed_app_repository import SQLAlchemyInstalledAppRepository
from services.conversation_service import ConversationService
from services.installed_app_access_service import InstalledAppAccessService
from services.installed_app_conversation_service import InstalledAppConversationService
from services.installed_app_generation_adapters import AppGenerateServiceRuntime
from services.installed_app_generation_service import InstalledAppGenerationService
from services.installed_app_message_adapters import InstalledAppMessageRuntime, emit_installed_app_feedback
from services.installed_app_message_service import InstalledAppMessageService
from services.installed_app_service import InstalledAppService, WorkspaceRoleLookup
from services.webapp_access_query_service import WebAppAccessQueryService
@dataclass(frozen=True, slots=True)
class InstalledAppServices:
access: InstalledAppAccessService
management: InstalledAppService
generation: InstalledAppGenerationService
conversations: InstalledAppConversationService
messages: InstalledAppMessageService
def _generate_installed_app_conversation_name(
*, tenant_id: str, app_id: str, conversation_id: str, query: str, app_mode: str
) -> str:
# Legacy provider and tracing lookups use db.session. Give them their own
# scope so teardown releases it before the conversation write transaction,
# without removing a session owned by the surrounding request.
with current_app.app_context():
return ConversationService.generate_name(
tenant_id=tenant_id, app_id=app_id, conversation_id=conversation_id, query=query, app_mode=app_mode
)
def build_installed_app_services(
*,
database_client: sessionmaker[Session],
webapp_access: WebAppAccessQueryService,
get_workspace_role: WorkspaceRoleLookup,
webapp_auth_enabled: bool,
) -> InstalledAppServices:
installed_apps = SQLAlchemyInstalledAppRepository(session_factory=database_client)
access = InstalledAppAccessService(
installed_apps=installed_apps,
is_user_allowed=webapp_access.is_user_allowed,
get_access_modes=webapp_access.batch_get_access_modes,
get_user_permissions=webapp_access.batch_get_user_permissions,
)
message_runtime = InstalledAppMessageRuntime(session_factory=database_client)
return InstalledAppServices(
access=access,
management=InstalledAppService(
installed_apps=installed_apps,
get_workspace_role=get_workspace_role,
get_visible_app_ids=access.get_visible_app_ids if webapp_auth_enabled else None,
),
generation=InstalledAppGenerationService(
usage=installed_apps,
runtime=AppGenerateServiceRuntime(session_factory=database_client),
),
conversations=InstalledAppConversationService(
conversations=SQLAlchemyInstalledAppConversationRepository(session_factory=database_client),
generate_name=_generate_installed_app_conversation_name,
enqueue_delete_cleanup=ConversationService.enqueue_delete_cleanup,
),
messages=InstalledAppMessageService(
messages=SQLAlchemyInstalledAppMessageRepository(session_factory=database_client),
get_extra_contents=message_runtime.get_extra_contents,
emit_feedback=emit_installed_app_feedback,
),
)