feat: add backup CLI commands, AI correction/modifier services, and timezone-aware date display
DevPlace CI / test (push) Failing after 25m18s
DevPlace CI / test (push) Failing after 25m18s
- Add `devplace backups` CLI subcommands (list, run, prune, clear) with job enqueueing and orphan cleanup - Introduce `BACKUPS_DIR` and `BACKUP_STAGING_DIR` config paths for backup storage - Implement `schedule_correction` and `schedule_modification` calls in content creation, comment creation, and comment editing flows - Add `DEFAULT_CORRECTION_PROMPT` and `DEFAULT_MODIFIER_PROMPT` config constants for AI content processing - Document timezone-aware date display using `local_dt`/`dt_ago` Jinja globals with client-side `Intl` localization - Update README with AI content correction/modifier support in direct messages via `@ai` inline instructions - Add `track_action(user["uid"], "vote")` call on upvote in `apply_vote`
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from .controller import AiModifierController
|
||||
|
||||
__all__ = ["AiModifierController"]
|
||||
@@ -0,0 +1,94 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from devplacepy.config import DEFAULT_MODIFIER_PROMPT
|
||||
from devplacepy.database import get_table
|
||||
from devplacepy.services.devii.errors import ToolInputError
|
||||
|
||||
logger = logging.getLogger("devii.ai_modifier")
|
||||
|
||||
|
||||
class AiModifierController:
|
||||
def __init__(self, owner_kind: str, owner_id: str) -> None:
|
||||
self._owner_kind = owner_kind
|
||||
self._owner_id = owner_id
|
||||
|
||||
async def dispatch(self, name: str, arguments: dict[str, Any]) -> str:
|
||||
if name == "ai_modifier_get":
|
||||
return self._get()
|
||||
if name == "ai_modifier_set":
|
||||
return self._set(arguments)
|
||||
raise ToolInputError(f"Unknown AI modifier tool: {name}")
|
||||
|
||||
def _require_user(self) -> None:
|
||||
if self._owner_kind != "user":
|
||||
raise ToolInputError(
|
||||
"AI modifier is only available for signed-in users."
|
||||
)
|
||||
|
||||
def _coerce_bool(self, raw: Any) -> bool:
|
||||
if isinstance(raw, bool):
|
||||
return raw
|
||||
return str(raw).strip().lower() in ("true", "1", "yes", "on")
|
||||
|
||||
def _value(self, arguments: dict[str, Any]) -> bool:
|
||||
return self._coerce_bool(arguments.get("enabled"))
|
||||
|
||||
def _user(self) -> dict[str, Any]:
|
||||
user = get_table("users").find_one(uid=self._owner_id)
|
||||
if not user:
|
||||
raise ToolInputError("User not found.")
|
||||
return user
|
||||
|
||||
def _get(self) -> str:
|
||||
self._require_user()
|
||||
user = self._user()
|
||||
return json.dumps(
|
||||
{
|
||||
"status": "success",
|
||||
"enabled": bool(user.get("ai_modifier_enabled")),
|
||||
"sync": bool(user.get("ai_modifier_sync")),
|
||||
"prompt": user.get("ai_modifier_prompt") or DEFAULT_MODIFIER_PROMPT,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
def _set(self, arguments: dict[str, Any]) -> str:
|
||||
self._require_user()
|
||||
user = self._user()
|
||||
enabled = 1 if self._value(arguments) else 0
|
||||
if "sync" in arguments and arguments.get("sync") is not None:
|
||||
sync = 1 if self._coerce_bool(arguments.get("sync")) else 0
|
||||
else:
|
||||
sync = 1 if user.get("ai_modifier_sync") else 0
|
||||
prompt_raw = arguments.get("prompt")
|
||||
if prompt_raw is None:
|
||||
prompt = user.get("ai_modifier_prompt") or DEFAULT_MODIFIER_PROMPT
|
||||
else:
|
||||
prompt = str(prompt_raw).strip()[:2000] or DEFAULT_MODIFIER_PROMPT
|
||||
get_table("users").update(
|
||||
{
|
||||
"uid": self._owner_id,
|
||||
"ai_modifier_enabled": enabled,
|
||||
"ai_modifier_sync": sync,
|
||||
"ai_modifier_prompt": prompt,
|
||||
},
|
||||
["uid"],
|
||||
)
|
||||
from devplacepy.utils import clear_user_cache
|
||||
|
||||
clear_user_cache(self._owner_id)
|
||||
return json.dumps(
|
||||
{
|
||||
"status": "success",
|
||||
"enabled": bool(enabled),
|
||||
"sync": bool(sync),
|
||||
"prompt": prompt,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
Reference in New Issue
Block a user