mirror of
https://github.com/langgenius/dify.git
synced 2026-09-06 01:04:49 +08:00
175 lines
4.9 KiB
Python
175 lines
4.9 KiB
Python
import json
|
|
from collections.abc import Mapping
|
|
from dataclasses import dataclass, replace
|
|
from datetime import datetime
|
|
from typing import Any, Protocol
|
|
|
|
from core.plugin.plugin_service import PluginService
|
|
from graphon.enums import WorkflowExecutionStatus
|
|
from models.enums import AppTriggerType
|
|
from services.workflow.entities import TriggerMetadata
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WorkflowAppLogAccount:
|
|
id: str
|
|
name: str
|
|
email: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WorkflowAppLogEndUser:
|
|
id: str
|
|
type: str
|
|
is_anonymous: bool
|
|
session_id: str | None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WorkflowAppLogRunSummary:
|
|
id: str
|
|
version: str | None
|
|
status: str
|
|
triggered_from: str
|
|
error: str | None
|
|
elapsed_time: float | None
|
|
total_tokens: int | None
|
|
total_steps: int | None
|
|
created_at: datetime | None
|
|
finished_at: datetime | None
|
|
exceptions_count: int | None
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WorkflowAppLogItem:
|
|
id: str
|
|
workflow_run: WorkflowAppLogRunSummary | None
|
|
details: dict[str, Any] | None
|
|
created_from: str
|
|
created_by_role: str
|
|
created_by_account: WorkflowAppLogAccount | None
|
|
created_by_end_user: WorkflowAppLogEndUser | None
|
|
created_at: datetime
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WorkflowAppLogPage:
|
|
page: int
|
|
limit: int
|
|
total: int
|
|
has_more: bool
|
|
data: tuple[WorkflowAppLogItem, ...]
|
|
|
|
|
|
class WorkflowAppLogQuery(Protocol):
|
|
def get_paginated(
|
|
self,
|
|
*,
|
|
tenant_id: str,
|
|
app_id: str,
|
|
keyword: str | None = None,
|
|
status: WorkflowExecutionStatus | None = None,
|
|
created_at_before: datetime | None = None,
|
|
created_at_after: datetime | None = None,
|
|
page: int = 1,
|
|
limit: int = 20,
|
|
detail: bool = False,
|
|
created_by_end_user_session_id: str | None = None,
|
|
created_by_account: str | None = None,
|
|
) -> WorkflowAppLogPage: ...
|
|
|
|
|
|
class WorkflowAppLogQueryService:
|
|
def __init__(
|
|
self,
|
|
*,
|
|
logs: WorkflowAppLogQuery,
|
|
) -> None:
|
|
self._logs = logs
|
|
|
|
def list_logs(
|
|
self,
|
|
*,
|
|
tenant_id: str,
|
|
app_id: str,
|
|
keyword: str | None = None,
|
|
status: WorkflowExecutionStatus | None = None,
|
|
created_at_before: datetime | None = None,
|
|
created_at_after: datetime | None = None,
|
|
page: int = 1,
|
|
limit: int = 20,
|
|
detail: bool = False,
|
|
created_by_end_user_session_id: str | None = None,
|
|
created_by_account: str | None = None,
|
|
) -> WorkflowAppLogPage:
|
|
result = self._logs.get_paginated(
|
|
tenant_id=tenant_id,
|
|
app_id=app_id,
|
|
keyword=keyword,
|
|
status=status,
|
|
created_at_before=created_at_before,
|
|
created_at_after=created_at_after,
|
|
page=page,
|
|
limit=limit,
|
|
detail=detail,
|
|
created_by_end_user_session_id=created_by_end_user_session_id,
|
|
created_by_account=created_by_account,
|
|
)
|
|
|
|
return WorkflowAppLogPage(
|
|
page=result.page,
|
|
limit=result.limit,
|
|
total=result.total,
|
|
has_more=result.has_more,
|
|
data=tuple(self._resolve_details(tenant_id=tenant_id, item=item) for item in result.data),
|
|
)
|
|
|
|
def _resolve_details(
|
|
self,
|
|
*,
|
|
tenant_id: str,
|
|
item: WorkflowAppLogItem,
|
|
) -> WorkflowAppLogItem:
|
|
if item.details is None:
|
|
return item
|
|
|
|
return replace(
|
|
item,
|
|
details={
|
|
"trigger_metadata": self._resolve_trigger_metadata(
|
|
tenant_id,
|
|
item.details.get("trigger_metadata"),
|
|
)
|
|
},
|
|
)
|
|
|
|
@staticmethod
|
|
def _resolve_trigger_metadata(
|
|
tenant_id: str,
|
|
value: str | Mapping[str, Any] | None,
|
|
) -> dict[str, Any]:
|
|
metadata = WorkflowAppLogQueryService._safe_json_loads(value)
|
|
if not metadata:
|
|
return {}
|
|
|
|
trigger_metadata = TriggerMetadata.model_validate(metadata)
|
|
if trigger_metadata.type == AppTriggerType.TRIGGER_PLUGIN:
|
|
icon = metadata.get("icon_filename")
|
|
icon_dark = metadata.get("icon_dark_filename")
|
|
metadata["icon"] = PluginService.get_plugin_icon_url(tenant_id=tenant_id, filename=icon) if icon else None
|
|
metadata["icon_dark"] = (
|
|
PluginService.get_plugin_icon_url(tenant_id=tenant_id, filename=icon_dark) if icon_dark else None
|
|
)
|
|
return metadata
|
|
|
|
@staticmethod
|
|
def _safe_json_loads(value: Any) -> Any:
|
|
if not value:
|
|
return None
|
|
if isinstance(value, str):
|
|
try:
|
|
return json.loads(value)
|
|
except Exception:
|
|
return None
|
|
return value
|