- 智能体支持从广场收藏到「我的」(新增 agent_favorites 表与收藏/取消收藏接口) - 定时任务新增「必须生成Markdown文件」开关:注入提示词并校验生成的 .md 文件且正文超过100字,否则记为失败(存于 execution_context,无需迁移) - 聊天问答展示时间(年月日 时分):问题在右下角、回答在左下角 - 常用提示词改为与账号绑定(新增 user_custom_prompts 表与 /api/user-prompts 接口),仅在首页输入框上方以居中标签 + 轮播展示,齿轮置于最右侧管理 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
"""SQLAlchemy-backed per-user custom prompt repository."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
|
|
|
from deerflow.persistence.user_prompts.model import UserCustomPromptRow
|
|
|
|
|
|
def _row_to_dict(row: UserCustomPromptRow) -> dict[str, Any]:
|
|
data = row.to_dict()
|
|
for key in ("created_at", "updated_at"):
|
|
value = data.get(key)
|
|
if isinstance(value, datetime):
|
|
data[key] = value.isoformat()
|
|
return data
|
|
|
|
|
|
class UserCustomPromptRepository:
|
|
def __init__(self, session_factory: async_sessionmaker[AsyncSession]) -> None:
|
|
self._sf = session_factory
|
|
|
|
async def list_for_user(self, user_id: str) -> list[dict[str, Any]]:
|
|
stmt = (
|
|
select(UserCustomPromptRow)
|
|
.where(UserCustomPromptRow.user_id == user_id)
|
|
.order_by(UserCustomPromptRow.sort_order.asc(), UserCustomPromptRow.created_at.asc())
|
|
)
|
|
async with self._sf() as session:
|
|
result = await session.execute(stmt)
|
|
return [_row_to_dict(row) for row in result.scalars()]
|
|
|
|
async def create(self, user_id: str, data: dict[str, Any]) -> dict[str, Any]:
|
|
now = datetime.now(UTC)
|
|
row = UserCustomPromptRow(
|
|
id=data["id"],
|
|
user_id=user_id,
|
|
title=data.get("title") or "",
|
|
content=data["content"],
|
|
sort_order=data.get("sort_order", 0),
|
|
created_at=now,
|
|
updated_at=now,
|
|
)
|
|
async with self._sf() as session:
|
|
session.add(row)
|
|
await session.commit()
|
|
await session.refresh(row)
|
|
return _row_to_dict(row)
|
|
|
|
async def update(self, prompt_id: str, user_id: str, data: dict[str, Any]) -> dict[str, Any] | None:
|
|
async with self._sf() as session:
|
|
row = await session.get(UserCustomPromptRow, prompt_id)
|
|
if row is None or row.user_id != user_id:
|
|
return None
|
|
for key in ("title", "content", "sort_order"):
|
|
if key in data:
|
|
setattr(row, key, data[key])
|
|
row.updated_at = datetime.now(UTC)
|
|
await session.commit()
|
|
await session.refresh(row)
|
|
return _row_to_dict(row)
|
|
|
|
async def delete(self, prompt_id: str, user_id: str) -> bool:
|
|
async with self._sf() as session:
|
|
row = await session.get(UserCustomPromptRow, prompt_id)
|
|
if row is None or row.user_id != user_id:
|
|
return False
|
|
await session.delete(row)
|
|
await session.commit()
|
|
return True
|