|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Request
|
|
from fastapi.responses import HTMLResponse, JSONResponse
|
|
|
|
from devplacepy.database import SEO_META_TYPES, get_seo_metadata
|
|
from devplacepy.schemas import SeoMetaOut
|
|
from devplacepy.services.seo_meta import defaults_for_target
|
|
from devplacepy.templating import templates
|
|
from devplacepy.seo import list_page_seo
|
|
from devplacepy.utils import get_current_user
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
TOOLS = [
|
|
{
|
|
"slug": "seo",
|
|
"name": "SEO Diagnostics",
|
|
"icon": "🔍",
|
|
"url": "/tools/seo",
|
|
"description": (
|
|
"Audit any URL or sitemap against a broad battery of technical, on-page, "
|
|
"structured-data, performance, accessibility and AI-readiness checks."
|
|
),
|
|
},
|
|
{
|
|
"slug": "deepsearch",
|
|
"name": "DeepSearch",
|
|
"icon": "🧠",
|
|
"url": "/tools/deepsearch",
|
|
"description": (
|
|
"Run a multi-agent deep web research job that crawls and indexes sources, "
|
|
"synthesises a cited report with confidence and gap analysis, then lets you "
|
|
"chat over the gathered evidence."
|
|
),
|
|
},
|
|
]
|
|
|
|
|
|
@router.get("", response_class=HTMLResponse)
|
|
async def tools_index(request: Request):
|
|
user = get_current_user(request)
|
|
seo_ctx = list_page_seo(
|
|
request,
|
|
title="Tools",
|
|
description="Developer tools on DevPlace, including the SEO Diagnostics auditor.",
|
|
breadcrumbs=[
|
|
{"name": "Home", "url": "/feed"},
|
|
{"name": "Tools", "url": "/tools"},
|
|
],
|
|
)
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"tools/index.html",
|
|
{**seo_ctx, "request": request, "user": user, "tools": TOOLS},
|
|
)
|
|
|
|
|
|
@router.get("/seo-meta/{target_type}/{target_uid}")
|
|
async def seo_meta_status(request: Request, target_type: str, target_uid: str):
|
|
if target_type not in SEO_META_TYPES:
|
|
return JSONResponse(
|
|
{"error": "unknown target type"}, status_code=400
|
|
)
|
|
if target_type == "project":
|
|
from devplacepy.content import can_view_project
|
|
from devplacepy.database import get_table
|
|
|
|
project = get_table("projects").find_one(uid=target_uid, deleted_at=None)
|
|
if not can_view_project(dict(project) if project else None, get_current_user(request)):
|
|
return JSONResponse({"error": "not found"}, status_code=404)
|
|
row = get_seo_metadata(target_type, target_uid)
|
|
if row:
|
|
payload = {
|
|
"uid": row.get("uid") or "",
|
|
"target_type": target_type,
|
|
"target_uid": target_uid,
|
|
"seo_title": row.get("seo_title") or "",
|
|
"seo_description": row.get("seo_description") or "",
|
|
"seo_keywords": row.get("seo_keywords") or "",
|
|
"status": row.get("status") or "ready",
|
|
"source": row.get("source") or "ai",
|
|
"generated_at": row.get("generated_at") or None,
|
|
}
|
|
else:
|
|
defaults = defaults_for_target(target_type, target_uid)
|
|
payload = {
|
|
"uid": "",
|
|
"target_type": target_type,
|
|
"target_uid": target_uid,
|
|
"seo_title": defaults["title"],
|
|
"seo_description": defaults["description"],
|
|
"seo_keywords": defaults["keywords"],
|
|
"status": "pending",
|
|
"source": "plain",
|
|
"generated_at": None,
|
|
}
|
|
return JSONResponse(SeoMetaOut(**payload).model_dump())
|