DEV Community

Subhendu Das
Subhendu Das

Posted on

AI content generation: the automated blog draft feature

Overview

DoAide Pulse gives indie developers a way to turn project documentation into publishable content without writing a line of copy. The Create from documents feature is the core of that promise. It lets a developer upload a Markdown or plain‑text file, optionally supply an LLM API key, and then queues a generation job that produces a ready‑to‑publish draft.

Problem

Writing marketing copy for a side project is a recurring pain point. A developer spends hours turning a README into a blog post, then re‑writes for social. The process is manual, error‑prone, and hard to schedule. On top of that, many developers use a custom LLM or a hosted model; the platform must respect that choice instead of forcing a single provider.

How It Works

The feature is built on a stack that mirrors the rest of DoAide Pulse:

  1. FastAPI endpoint – Accepts a file upload and an optional llm_key field. The request is authenticated via a JWT issued by the dashboard.
  2. SQLAlchemy model – Stores the draft in a drafts table with columns for project_id, source_path, llm_provider, llm_key_hash, and status.
  3. Celery worker – Picks up the draft, loads the LLM key from the database, and streams a prompt that instructs the model to convert the source document into a blog‑ready article.
  4. Redis queue – Ensures the generation job is processed asynchronously, freeing the API from long‑running calls.
  5. Post‑processing – After generation, the worker runs a quick lint pass to fix Markdown syntax, adds front‑matter tags, and pushes the result to a content calendar entry.
  6. Dev.to API – When the user approves the draft, a FastAPI route triggers an authenticated call to the Dev.to endpoint, posting the article with the correct tags and scheduled time.

Code Snippet: FastAPI Route

from fastapi import APIRouter, File, Form, UploadFile, Depends
from sqlalchemy.orm import Session
from app.db import get_db
from app.models import Draft

router = APIRouter()

@router.post("/drafts/", status_code=202)
async def create_draft(
    file: UploadFile = File(...),
    llm_key: str = Form(None),
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    content = await file.read()
    draft = Draft(
        project_id=user.project_id,
        source_path=file.filename,
        llm_provider="custom",
        llm_key_hash=hash_key(llm_key),
        status="queued",
    )
    db.add(draft)
    db.commit()
    celery_app.send_task("tasks.generate_draft", args=[draft.id])
    return {"detail": "Draft queued for generation"}
Enter fullscreen mode Exit fullscreen mode


This is where marketing automation pays off in practice.

Code Snippet: Celery Task

from celery import shared_task
from app.db import get_db
from app.models import Draft
from app.llm import generate_from_docs

@shared_task
def generate_draft(draft_id: int):
    db = get_db()
    draft = db.query(Draft).filter(Draft.id == draft_id).one()
    llm_key = decrypt_key(draft.llm_key_hash)
    result = generate_from_docs(draft.source_path, llm_key)
    draft.generated_content = result
    draft.status = "ready"
    db.commit()
Enter fullscreen mode Exit fullscreen mode


Getting marketing automation right early saves rework later.

Using It

  1. Upload – From the dashboard’s Drafts tab, click Create from documents, choose a file, and optionally paste your LLM API key.
  2. Queue – The UI shows a spinner and a status badge that updates from queued → processing → ready.
  3. Review – Once ready, the draft appears in the Content Calendar with a preview. You can edit the Markdown, adjust tags, or change the scheduled publish time.
  4. Approve – Hit Publish; the system calls the Dev.to API, logs the article URL, and updates the dashboard with the live link.

The entire flow takes a few seconds for the API call, a few minutes for generation (depending on the LLM), and then instant posting. No manual copy‑paste or external tooling is required. Good marketing automation keeps the rest of the workflow predictable.

Technical Details

  • FastAPI handles HTTP and WebSocket endpoints, providing low‑latency routing.
  • SQLAlchemy maps the drafts table to a Python class, enabling migrations via Alembic.
  • Celery + Redis decouple the long‑running generation from the request‑response cycle.
  • React + Vite + Tailwind CSS render the dashboard; the Drafts component fetches status via a polling hook.
  • PostgreSQL stores draft metadata and content; migrations include a CHECK constraint to ensure status values are valid.
  • Dev.to API integration uses the devto Python package (or raw requests) with OAuth scopes for publishing.

The commit log shows recent fixes that directly benefit this feature: automatic SEO preflight fixes, dashboard bug patches, and analytics pipeline health checks. These improvements mean that every generated draft is already SEO‑ready and that the UI remains stable even under load. Treat marketing automation as a habit rather than a one-off task.

Conclusion

By turning raw documentation into polished blog posts, the Create from documents feature removes the friction that typically deters indie developers from marketing their work. It leverages the same core stack that powers DoAide Pulse’s scheduling, publishing, and analytics, ensuring a consistent developer experience across the platform.

Related reading

Top comments (0)