171 lines
6.8 KiB
Python
171 lines
6.8 KiB
Python
from __future__ import annotations
|
|
|
|
from .shared import *
|
|
|
|
class TaskBriefBundleCrudMixin:
|
|
@classmethod
|
|
async def _get_or_init_bundle(cls, db: AsyncSession, *, tenant_id: int) -> tuple[Integration, dict[str, Any]]:
|
|
row = (
|
|
await db.execute(
|
|
select(Integration).where(
|
|
and_(
|
|
Integration.tenant_id == int(tenant_id),
|
|
Integration.type == INTEGRATION_TYPE,
|
|
)
|
|
)
|
|
)
|
|
).scalar_one_or_none()
|
|
if row is None:
|
|
row = Integration(
|
|
tenant_id=int(tenant_id),
|
|
type=INTEGRATION_TYPE,
|
|
is_active=True,
|
|
config={
|
|
"templates": [],
|
|
"runs": [],
|
|
"briefs": [],
|
|
},
|
|
)
|
|
db.add(row)
|
|
await db.flush()
|
|
|
|
bundle = cls._safe_dict(row.config)
|
|
changed = False
|
|
for key in ("templates", "runs", "briefs"):
|
|
if not isinstance(bundle.get(key), list):
|
|
bundle[key] = []
|
|
changed = True
|
|
|
|
existing_templates = [item for item in bundle.get("templates", []) if isinstance(item, dict)]
|
|
if not existing_templates:
|
|
bundle["templates"] = cls._build_system_templates()
|
|
existing_templates = [item for item in bundle["templates"] if isinstance(item, dict)]
|
|
changed = True
|
|
else:
|
|
upgraded_default_template = False
|
|
latest_default_content = cls._load_default_template_content()
|
|
for item in existing_templates:
|
|
if str(item.get("id") or "") != DEFAULT_TEMPLATE_ID:
|
|
continue
|
|
current_content = str(item.get("content") or "").strip()
|
|
if current_content and not cls._is_default_template_fallback(current_content):
|
|
break
|
|
item["name"] = str(item.get("name") or "").strip() or DEFAULT_TEMPLATE_NAME
|
|
item["description"] = str(item.get("description") or "").strip() or DEFAULT_TEMPLATE_DESCRIPTION
|
|
item["content"] = latest_default_content
|
|
item["updated_at"] = now_cn_naive().isoformat()
|
|
if item.get("updated_by") is None:
|
|
item["updated_by"] = 0
|
|
upgraded_default_template = True
|
|
break
|
|
if upgraded_default_template:
|
|
bundle["templates"] = existing_templates
|
|
changed = True
|
|
|
|
existing_templates, added_presets = cls._ensure_system_templates(existing_templates)
|
|
if added_presets:
|
|
bundle["templates"] = existing_templates
|
|
changed = True
|
|
|
|
existing_briefs = [item for item in bundle.get("briefs", []) if isinstance(item, dict)]
|
|
existing_runs = [item for item in bundle.get("runs", []) if isinstance(item, dict)]
|
|
if not existing_briefs and not existing_runs:
|
|
seed_briefs, seed_runs = cls._load_seed_history()
|
|
if seed_briefs and seed_runs:
|
|
bundle["briefs"] = seed_briefs
|
|
bundle["runs"] = seed_runs
|
|
changed = True
|
|
|
|
if changed:
|
|
row.config = bundle
|
|
await db.flush()
|
|
return row, bundle
|
|
|
|
@staticmethod
|
|
def _sort_by_time_desc(items: list[dict[str, Any]], key: str = "created_at") -> list[dict[str, Any]]:
|
|
return sorted(items, key=lambda x: str(x.get(key) or ""), reverse=True)
|
|
|
|
@classmethod
|
|
async def list_center(cls, db: AsyncSession, *, tenant_id: int) -> list[dict[str, Any]]:
|
|
_, bundle = await cls._get_or_init_bundle(db, tenant_id=tenant_id)
|
|
briefs = [dict(item) for item in bundle.get("briefs", []) if isinstance(item, dict)]
|
|
return cls._sort_by_time_desc(briefs, key="created_at")
|
|
|
|
@classmethod
|
|
async def list_templates(cls, db: AsyncSession, *, tenant_id: int) -> list[dict[str, Any]]:
|
|
_, bundle = await cls._get_or_init_bundle(db, tenant_id=tenant_id)
|
|
templates = [dict(item) for item in bundle.get("templates", []) if isinstance(item, dict)]
|
|
return cls._sort_by_time_desc(templates, key="updated_at")
|
|
|
|
@classmethod
|
|
async def create_template(
|
|
cls,
|
|
db: AsyncSession,
|
|
*,
|
|
tenant_id: int,
|
|
operator_user_id: int,
|
|
name: str,
|
|
content: str,
|
|
description: Optional[str] = None,
|
|
) -> dict[str, Any]:
|
|
row, bundle = await cls._get_or_init_bundle(db, tenant_id=tenant_id)
|
|
now_text = now_cn_naive().isoformat()
|
|
item = {
|
|
"id": f"tpl_{uuid4().hex[:12]}",
|
|
"name": str(name or "").strip()[:120] or "默认模板",
|
|
"description": str(description or "").strip()[:300] or None,
|
|
"content": str(content or "").strip(),
|
|
"updated_at": now_text,
|
|
"updated_by": int(operator_user_id),
|
|
"created_at": now_text,
|
|
}
|
|
templates = bundle.get("templates") if isinstance(bundle.get("templates"), list) else []
|
|
templates.append(item)
|
|
bundle["templates"] = templates
|
|
row.config = bundle
|
|
await db.flush()
|
|
return item
|
|
|
|
@classmethod
|
|
async def update_template(
|
|
cls,
|
|
db: AsyncSession,
|
|
*,
|
|
tenant_id: int,
|
|
operator_user_id: int,
|
|
template_id: str,
|
|
name: Optional[str] = None,
|
|
content: Optional[str] = None,
|
|
description: Optional[str] = None,
|
|
) -> dict[str, Any] | None:
|
|
row, bundle = await cls._get_or_init_bundle(db, tenant_id=tenant_id)
|
|
templates = bundle.get("templates") if isinstance(bundle.get("templates"), list) else []
|
|
target = None
|
|
for item in templates:
|
|
if not isinstance(item, dict):
|
|
continue
|
|
if str(item.get("id") or "") == str(template_id or ""):
|
|
target = item
|
|
break
|
|
if target is None:
|
|
return None
|
|
if name is not None:
|
|
target["name"] = str(name or "").strip()[:120] or target.get("name") or "默认模板"
|
|
if content is not None:
|
|
target["content"] = str(content or "").strip()
|
|
if description is not None:
|
|
target["description"] = str(description or "").strip()[:300] or None
|
|
target["updated_at"] = now_cn_naive().isoformat()
|
|
target["updated_by"] = int(operator_user_id)
|
|
bundle["templates"] = templates
|
|
row.config = bundle
|
|
await db.flush()
|
|
return dict(target)
|
|
|
|
@classmethod
|
|
async def list_runs(cls, db: AsyncSession, *, tenant_id: int) -> list[dict[str, Any]]:
|
|
_, bundle = await cls._get_or_init_bundle(db, tenant_id=tenant_id)
|
|
runs = [dict(item) for item in bundle.get("runs", []) if isinstance(item, dict)]
|
|
return cls._sort_by_time_desc(runs, key="generated_at")
|
|
|