|
# retoor <retoor@molodetz.nl>
|
|
|
|
from .._shared import endpoint, field
|
|
|
|
GROUP = {
|
|
"slug": "tools",
|
|
"title": "Tools (SEO & DeepSearch)",
|
|
"intro": """
|
|
# Tools: SEO Diagnostics & DeepSearch
|
|
|
|
Two public developer tools that run as background jobs.
|
|
|
|
**SEO Diagnostics** audits a URL or sitemap with a headless browser and runs a broad battery of
|
|
technical, on-page, structured-data, Core Web Vitals, accessibility and AI-readiness checks.
|
|
|
|
**DeepSearch** is a multi-agent deep web researcher that crawls and indexes sources, then
|
|
synthesises a cited report with confidence scoring and gap analysis, plus a grounded chat over
|
|
the results.
|
|
|
|
Every endpoint follows the shared [Conventions & Errors](/docs/conventions.html). These are
|
|
**capability URLs**: the job `uid` is an unguessable identifier, so anyone holding it can read the
|
|
status and report.
|
|
""",
|
|
"endpoints": [
|
|
endpoint(
|
|
id="tools-seo-run",
|
|
method="POST",
|
|
path="/tools/seo/run",
|
|
title="Queue an SEO audit",
|
|
summary="Start a background SEO audit of a URL or sitemap. Returns the job uid plus status and websocket URLs.",
|
|
auth="public",
|
|
encoding="form",
|
|
params=[
|
|
field("url", "form", "string", True, "https://example.com", "Page URL or sitemap.xml URL to audit."),
|
|
field("mode", "form", "enum", False, "url", "'url' (single page) or 'sitemap' (crawl).", ["url", "sitemap"]),
|
|
field("max_pages", "form", "integer", False, "10", "Max pages to crawl in sitemap mode (1-50)."),
|
|
],
|
|
sample_response={
|
|
"uid": "SEO_JOB_UID",
|
|
"status_url": "/tools/seo/SEO_JOB_UID",
|
|
"ws_url": "/tools/seo/SEO_JOB_UID/ws",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-seo-status",
|
|
method="GET",
|
|
path="/tools/seo/{uid}",
|
|
title="SEO audit status",
|
|
summary="Poll an SEO audit. Once done, score, grade and report_url are populated.",
|
|
auth="public",
|
|
params=[
|
|
field("uid", "path", "string", True, "SEO_JOB_UID", "SEO job uid returned when the audit was queued."),
|
|
],
|
|
sample_response={
|
|
"uid": "SEO_JOB_UID",
|
|
"kind": "seo",
|
|
"status": "done",
|
|
"target": "https://example.com",
|
|
"mode": "url",
|
|
"ws_url": "/tools/seo/SEO_JOB_UID/ws",
|
|
"report_url": "/tools/seo/SEO_JOB_UID/report",
|
|
"score": 82,
|
|
"grade": "B",
|
|
"page_count": 1,
|
|
"error": None,
|
|
"created_at": "2026-06-14T10:00:00+00:00",
|
|
"completed_at": "2026-06-14T10:00:18+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-seo-report",
|
|
method="GET",
|
|
path="/tools/seo/{uid}/report",
|
|
title="SEO audit report",
|
|
summary="Full categorised report: overall score, per-category subscores, and every check with its recommendation. Negotiates HTML or JSON.",
|
|
auth="public",
|
|
params=[
|
|
field("uid", "path", "string", True, "SEO_JOB_UID", "SEO job uid of a finished audit."),
|
|
],
|
|
sample_response={
|
|
"uid": "SEO_JOB_UID",
|
|
"status": "done",
|
|
"target": "https://example.com",
|
|
"score": 82,
|
|
"grade": "B",
|
|
"page_count": 1,
|
|
"counts": {"pass": 40, "warn": 8, "fail": 3, "info": 5, "skip": 0},
|
|
"categories": {"crawlability": {"score": 90, "pass": 9, "warn": 1, "fail": 0}},
|
|
"pages": [{"url": "https://example.com", "status": 200, "score": 82, "grade": "B"}],
|
|
"checks": [
|
|
{
|
|
"id": "meta.title_present",
|
|
"category": "meta",
|
|
"title": "Title tag",
|
|
"status": "pass",
|
|
"severity": "high",
|
|
"value": "Example Domain",
|
|
"recommendation": "",
|
|
"url": "https://example.com",
|
|
}
|
|
],
|
|
"site": {"robots": {"status": 200}, "sitemap": {"status": 200, "url_count": 12}},
|
|
"generated_at": "2026-06-14T10:00:18+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-seo-screenshot",
|
|
method="GET",
|
|
path="/tools/seo/{uid}/screenshot/{index}",
|
|
title="SEO audit page screenshot",
|
|
summary="Stream the rendered screenshot (image/png) captured for the audited page at the given zero-based index.",
|
|
auth="public",
|
|
interactive=True,
|
|
params=[
|
|
field("uid", "path", "string", True, "SEO_JOB_UID", "SEO job uid of a finished audit."),
|
|
field("index", "path", "integer", True, "0", "Zero-based index of the audited page."),
|
|
],
|
|
),
|
|
endpoint(
|
|
id="tools-seo-meta-status",
|
|
method="GET",
|
|
path="/tools/seo-meta/{target_type}/{target_uid}",
|
|
title="Generated SEO metadata for a content item",
|
|
summary="Read the clean, AI-generated SEO title, description and keywords for a published post, project, gist, news article or issue. Returns a plain-content default with status 'pending' until the AI value is ready.",
|
|
auth="public",
|
|
params=[
|
|
field("target_type", "path", "enum", True, "post", "Content type.", ["post", "project", "gist", "news", "issue"]),
|
|
field("target_uid", "path", "string", True, "CONTENT_UID", "The content uid (or issue number)."),
|
|
],
|
|
sample_response={
|
|
"uid": "SEO_META_UID",
|
|
"target_type": "post",
|
|
"target_uid": "CONTENT_UID",
|
|
"seo_title": "Building a fast SQLite social network",
|
|
"seo_description": "How DevPlace keeps SQLite synchronous and still serves a developer social network fast, with WAL, mmap and batch query helpers.",
|
|
"seo_keywords": "sqlite, fastapi, social network, performance, wal",
|
|
"status": "ready",
|
|
"source": "ai",
|
|
"generated_at": "2026-06-14T10:00:18+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-deepsearch-run",
|
|
method="POST",
|
|
path="/tools/deepsearch/run",
|
|
title="Queue a DeepSearch research job",
|
|
summary="Start a multi-agent deep web research job. Returns the job uid plus status and websocket URLs. Connect ws_url for live progress frames.",
|
|
auth="public",
|
|
encoding="form",
|
|
params=[
|
|
field("query", "form", "string", True, "history of the transistor", "The research question to investigate."),
|
|
field("depth", "form", "integer", False, "2", "Research depth (1-4)."),
|
|
field("max_pages", "form", "integer", False, "12", "Maximum sources to crawl (1-30)."),
|
|
],
|
|
sample_response={
|
|
"uid": "DEEPSEARCH_JOB_UID",
|
|
"status_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID",
|
|
"ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/ws",
|
|
"progress_frames_note": (
|
|
"The ws_url stream emits newline-delimited JSON frames; the set is append-only "
|
|
"and the first frame carries version:1. Each frame has a type: phase "
|
|
"(phase, index, total, label), stage, substep (planning angles), queries, "
|
|
"candidates, rsearch, progress (done, total, url), page_loaded (source, render, "
|
|
"elapsed_ms, done, total), page_cached, page_skipped (reason), page_duplicate, "
|
|
"embed_batch (batch, total_batches, backend, done, total), embed_done (backend, "
|
|
"chunk_count), agent (agent, status start|done, elapsed_ms, tokens_in, tokens_out), "
|
|
"report_ready, done (session_url), failed (message)."
|
|
),
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-deepsearch-status",
|
|
method="GET",
|
|
path="/tools/deepsearch/{uid}",
|
|
title="DeepSearch status",
|
|
summary="Poll a DeepSearch job. Once done, score, confidence and session_url are populated.",
|
|
auth="public",
|
|
params=[
|
|
field("uid", "path", "string", True, "DEEPSEARCH_JOB_UID", "DeepSearch job uid returned when the run was queued."),
|
|
],
|
|
sample_response={
|
|
"uid": "DEEPSEARCH_JOB_UID",
|
|
"kind": "deepsearch",
|
|
"status": "done",
|
|
"query": "history of the transistor",
|
|
"depth": 2,
|
|
"max_pages": 12,
|
|
"ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/ws",
|
|
"chat_ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/chat",
|
|
"session_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/session",
|
|
"score": 78,
|
|
"confidence": 0.72,
|
|
"source_diversity": 0.64,
|
|
"page_count": 11,
|
|
"chunk_count": 240,
|
|
"error": None,
|
|
"created_at": "2026-06-14T10:00:00+00:00",
|
|
"completed_at": "2026-06-14T10:01:40+00:00",
|
|
},
|
|
),
|
|
endpoint(
|
|
id="tools-deepsearch-session",
|
|
method="GET",
|
|
path="/tools/deepsearch/{uid}/session",
|
|
title="DeepSearch report",
|
|
summary="Full cited research report: summary, findings, gaps, sources and metrics. Negotiates HTML or JSON.",
|
|
auth="public",
|
|
params=[
|
|
field("uid", "path", "string", True, "DEEPSEARCH_JOB_UID", "DeepSearch job uid of a finished run."),
|
|
],
|
|
sample_response={
|
|
"uid": "DEEPSEARCH_JOB_UID",
|
|
"status": "done",
|
|
"query": "history of the transistor",
|
|
"score": 78,
|
|
"confidence": 0.72,
|
|
"source_diversity": 0.64,
|
|
"page_count": 11,
|
|
"chunk_count": 240,
|
|
"summary": "The transistor was invented at Bell Labs in 1947...",
|
|
"findings": [
|
|
{"title": "Invention", "detail": "...", "confidence": 0.8, "citations": [1]}
|
|
],
|
|
"gaps": ["Limited coverage of later MOSFET developments."],
|
|
"sources": [{"url": "https://example.com", "title": "Example", "source": "httpx"}],
|
|
"chat_ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/chat",
|
|
"export_md_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.md",
|
|
"export_json_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.json",
|
|
"export_pdf_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.pdf",
|
|
},
|
|
),
|
|
],
|
|
}
|