feat: add backup CLI commands, AI correction/modifier services, and timezone-aware date display

- 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:
2026-06-16 03:32:19 +00:00
parent e59bc2d34e
commit 15bd4ad87c
115 changed files with 5839 additions and 187 deletions
+28
View File
@@ -2,12 +2,40 @@
import logging
from devplacepy.database import get_correction_usage, get_modifier_usage
from devplacepy.services.manager import service_manager
from devplacepy.services.openai_gateway.analytics import user_spend_24h
logger = logging.getLogger(__name__)
def _usage_view(data: dict, include_cost: bool) -> dict:
usage = {
"calls": data["calls"],
"prompt_tokens": data["prompt_tokens"],
"completion_tokens": data["completion_tokens"],
"total_tokens": data["total_tokens"],
"avg_tokens": data["avg_tokens"],
"avg_latency_ms": data["avg_upstream_latency_ms"],
"avg_total_latency_ms": data["avg_total_latency_ms"],
"avg_tokens_per_second": data["avg_tokens_per_second"],
"total_time_s": round(data["upstream_latency_ms"] / 1000.0, 1),
"last_used": data["updated_at"],
}
if include_cost:
usage["cost_usd"] = round(data["cost_usd"], 6)
usage["avg_cost_usd"] = round(data["avg_cost_usd"], 6)
return usage
def _correction_usage(user_uid: str, include_cost: bool = False) -> dict:
return _usage_view(get_correction_usage(user_uid), include_cost)
def _modifier_usage(user_uid: str, include_cost: bool = False) -> dict:
return _usage_view(get_modifier_usage(user_uid), include_cost)
def _ai_quota(
user_uid: str, include_cost: bool = False, is_admin: bool = False
) -> dict | None: