Add link building API endpoint and skill file
- /api/linkbuilding/status endpoint returns pending, in-progress, completed, and failed pipeline states for dashboard consumption - skills/linkbuilding.md with YAML frontmatter linking tools and agents - Skill body documents workflow, triggers, default flags, and ClickUp fields Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>cora-start
parent
90e79b77ab
commit
0f4c77adc9
|
|
@ -1,6 +1,8 @@
|
||||||
"""Entry point: python -m cheddahbot"""
|
"""Entry point: python -m cheddahbot"""
|
||||||
|
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from .agent import Agent
|
from .agent import Agent
|
||||||
from .agent_registry import AgentRegistry
|
from .agent_registry import AgentRegistry
|
||||||
|
|
@ -131,13 +133,108 @@ def main():
|
||||||
log.warning("Scheduler not available: %s", e)
|
log.warning("Scheduler not available: %s", e)
|
||||||
|
|
||||||
log.info("Launching Gradio UI on %s:%s...", config.host, config.port)
|
log.info("Launching Gradio UI on %s:%s...", config.host, config.port)
|
||||||
app = create_ui(registry, config, default_llm, notification_bus=notification_bus)
|
blocks = create_ui(registry, config, default_llm, notification_bus=notification_bus)
|
||||||
app.launch(
|
|
||||||
server_name=config.host,
|
# Build a parent FastAPI app so we can mount the dashboard alongside Gradio.
|
||||||
server_port=config.port,
|
# Inserting routes into blocks.app before launch() doesn't work because
|
||||||
pwa=True,
|
# launch()/mount_gradio_app() replaces the internal App instance.
|
||||||
show_error=True,
|
import gradio as gr
|
||||||
|
import uvicorn
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.responses import RedirectResponse
|
||||||
|
from starlette.staticfiles import StaticFiles
|
||||||
|
|
||||||
|
fastapi_app = FastAPI()
|
||||||
|
|
||||||
|
# Mount the dashboard as static files (must come before Gradio's catch-all)
|
||||||
|
dashboard_dir = Path(__file__).resolve().parent.parent / "dashboard"
|
||||||
|
if dashboard_dir.is_dir():
|
||||||
|
# Redirect /dashboard (no trailing slash) → /dashboard/
|
||||||
|
@fastapi_app.get("/dashboard")
|
||||||
|
async def _dashboard_redirect():
|
||||||
|
return RedirectResponse(url="/dashboard/")
|
||||||
|
|
||||||
|
fastapi_app.mount(
|
||||||
|
"/dashboard",
|
||||||
|
StaticFiles(directory=str(dashboard_dir), html=True),
|
||||||
|
name="dashboard",
|
||||||
)
|
)
|
||||||
|
log.info("Dashboard mounted at /dashboard/ (serving %s)", dashboard_dir)
|
||||||
|
|
||||||
|
# Link building status API endpoint (for dashboard consumption)
|
||||||
|
@fastapi_app.get("/api/linkbuilding/status")
|
||||||
|
async def linkbuilding_status():
|
||||||
|
"""Return link building pipeline status for dashboard consumption."""
|
||||||
|
result = {
|
||||||
|
"pending_cora_runs": [],
|
||||||
|
"in_progress": [],
|
||||||
|
"completed": [],
|
||||||
|
"failed": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Query KV store for tracked link building states
|
||||||
|
try:
|
||||||
|
for key, value in db.kv_scan("linkbuilding:watched:"):
|
||||||
|
try:
|
||||||
|
state = json.loads(value)
|
||||||
|
entry = {
|
||||||
|
"filename": state.get("filename", key.split(":")[-1]),
|
||||||
|
"status": state.get("status", "unknown"),
|
||||||
|
"task_id": state.get("task_id", ""),
|
||||||
|
}
|
||||||
|
if state.get("status") == "completed":
|
||||||
|
entry["completed_at"] = state.get("completed_at", "")
|
||||||
|
result["completed"].append(entry)
|
||||||
|
elif state.get("status") == "failed":
|
||||||
|
entry["error"] = state.get("error", "")
|
||||||
|
entry["failed_at"] = state.get("failed_at", "")
|
||||||
|
result["failed"].append(entry)
|
||||||
|
elif state.get("status") == "processing":
|
||||||
|
entry["started_at"] = state.get("started_at", "")
|
||||||
|
result["in_progress"].append(entry)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("Error reading linkbuilding KV state: %s", e)
|
||||||
|
|
||||||
|
# Query ClickUp for pending tasks (to do + Link Building + Cora Backlinks)
|
||||||
|
if config.clickup.enabled:
|
||||||
|
try:
|
||||||
|
from .clickup import ClickUpClient
|
||||||
|
|
||||||
|
cu = ClickUpClient(
|
||||||
|
api_token=config.clickup.api_token,
|
||||||
|
workspace_id=config.clickup.workspace_id,
|
||||||
|
task_type_field_name=config.clickup.task_type_field_name,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
tasks = cu.get_tasks_from_space(
|
||||||
|
config.clickup.space_id, statuses=["to do"]
|
||||||
|
)
|
||||||
|
for task in tasks:
|
||||||
|
if task.task_type != "Link Building":
|
||||||
|
continue
|
||||||
|
lb_method = task.custom_fields.get("LB Method", "")
|
||||||
|
if lb_method and lb_method != "Cora Backlinks":
|
||||||
|
continue
|
||||||
|
result["pending_cora_runs"].append({
|
||||||
|
"keyword": task.custom_fields.get("Keyword", ""),
|
||||||
|
"url": task.custom_fields.get("IMSURL", ""),
|
||||||
|
"client": task.custom_fields.get("Client", ""),
|
||||||
|
"task_id": task.id,
|
||||||
|
"task_name": task.name,
|
||||||
|
})
|
||||||
|
finally:
|
||||||
|
cu.close()
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("Error querying ClickUp for pending link building: %s", e)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Mount Gradio at the root
|
||||||
|
gr.mount_gradio_app(fastapi_app, blocks, path="/", pwa=True, show_error=True)
|
||||||
|
|
||||||
|
uvicorn.run(fastapi_app, host=config.host, port=config.port)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
name: link-building
|
||||||
|
description: Automated link building pipeline using Big-Link-Man CLI. Orchestrates CORA report ingestion and content generation for tiered link building campaigns. Use when the user asks about link building, Cora backlinks, content generation for SEO, or managing the link building pipeline.
|
||||||
|
tools: [run_link_building, run_cora_backlinks, blm_ingest_cora, blm_generate_batch, scan_cora_folder]
|
||||||
|
agents: [link_builder, default]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Link Building Pipeline
|
||||||
|
|
||||||
|
This skill automates the link building workflow using the Big-Link-Man CLI tool. It handles CORA report ingestion and batch content generation for tiered backlink campaigns.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### Full Pipeline (Cora Backlinks)
|
||||||
|
|
||||||
|
1. **Ingest CORA Report**: Parse a `.xlsx` CORA report to create a project with keyword data, entities, and related searches
|
||||||
|
2. **Generate Content Batch**: Produce tiered content articles based on the ingested project data
|
||||||
|
|
||||||
|
### Triggers
|
||||||
|
|
||||||
|
- **Folder Watcher**: Automatically picks up new `.xlsx` files from `Z:/cora-inbox` and matches them to ClickUp tasks by keyword
|
||||||
|
- **Chat Command**: User can directly request link building via chat (e.g., "Run link building for precision-cnc-machining.xlsx")
|
||||||
|
- **ClickUp Task**: Tasks with Work Category = "Link Building" are tracked and executed when a matching CORA file appears
|
||||||
|
|
||||||
|
### Default Flags
|
||||||
|
|
||||||
|
- `-m` (money site URL): Always passed to prevent interactive prompts
|
||||||
|
- `-bp` (branded plus ratio): Defaults to 0.7 unless overridden
|
||||||
|
- `--continue-on-error`: Always set on generate-batch
|
||||||
|
|
||||||
|
### Available Tools
|
||||||
|
|
||||||
|
- `run_link_building` — Orchestrator that routes to the correct pipeline based on LB Method
|
||||||
|
- `run_cora_backlinks` — Full pipeline: ingest + generate
|
||||||
|
- `blm_ingest_cora` — Standalone ingest (creates project, returns job file)
|
||||||
|
- `blm_generate_batch` — Standalone generate (processes existing job file)
|
||||||
|
- `scan_cora_folder` — Check what's in the watch folder and their processing status
|
||||||
|
|
||||||
|
### ClickUp Integration
|
||||||
|
|
||||||
|
Link building tasks use these custom fields:
|
||||||
|
- **LB Method**: Pipeline type (currently "Cora Backlinks")
|
||||||
|
- **Keyword**: Target keyword (used for file matching)
|
||||||
|
- **IMSURL**: Money site URL
|
||||||
|
- **CustomAnchors**: Comma-separated anchor text overrides
|
||||||
|
- **BrandedPlusRatio**: Override for branded+ ratio
|
||||||
|
- **CLIFlags**: Additional CLI flags
|
||||||
|
- **CoraFile**: Path to .xlsx file (set by agent after match)
|
||||||
Loading…
Reference in New Issue