Skip to content

About

Lightweight AI Model Design

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

Repository files navigation

OrganicForge

Local-first, organic digital-marketing automation re-engineered as a visual Drag-and-Drop Workflow Builder. Drag modular blocks onto a canvas, wire them together, and run them sequentially — powered by a dual-routing SLM fleet with a strict 3000MB RAM ceiling and automatic offload to external GPU servers.

Runs 24/7 on a 16GB Linux partition alongside n8n, SearXNG, and ChromaDB. No cloud tokens required. OOM-safe under any n8n concurrency burst.


What is OrganicForge?

OrganicForge is the backend orchestration engine for a visual marketing-workflow builder. You (or an external n8n workflow) define a graph of marketing nodes — SEO Auditor, Content Generator, Live Web Search, Social Poster — and the engine executes them in topological order, passing data down the wires, with every node powered by the right local model for the job.

The engine is built for a two-host fleet architecture:

Host RAM Role What runs here
Linux partition 16GB (single stick) 24/7 automation host OrganicForge API + 2 local SLMs + n8n + SearXNG + ChromaDB
Windows host 32GB + 6GB VRAM Heavy compute + GPU offload kilocode extension server (laguna/mimo/nemotron/ling) + opencode proxy (Gemma-2-9B, DeepSeek-R1-8B)

The Linux box never loads a model heavier than 2.6GB. Everything else is routed over the LAN to the Windows host's OpenAI-compatible servers — zero local RAM cost during heavy n8n bursts.


The v2.2 locked fleet

Local SLMs (only 2 GGUFs on the Linux box)

Model Role Quant RAM Used for
phi-4-mini (3.8B) fast_logic Q4_K_M 2.6GB SEO audits, URL parsing, structural logic
Llama-3.2-3B-Instruct creative_copywriting Q4_K_M 2.2GB Social posts, email copywriting

Only one is resident at a time. The engine unloads (Llama.close() + dual gc.collect()) before loading the next, so peak RSS stays under the 3000MB ceiling.

External providers (Windows host, zero local RAM)

Provider Endpoint Models → Roles
kilocode http://192.168.1.10:1234/v1 laguna→creative, mimo→fast_logic, nemotron→strategic_reasoning, ling→json_structured
opencode http://192.168.1.10:8081/v1 gemma-2-9b→creative, deepseek-r1-8b→strategic_reasoning

The json_structured and strategic_reasoning roles have no local GGUF — they always route to the Windows host.

Dual-routing logic

generate() decides local-vs-external in this order:

  1. Explicit external key ("kilocode:laguna") → call external directly
  2. Role has no local GGUF (json_structured, strategic_reasoning) → must route external
  3. n8n burst active (≥3 concurrent requests) → route ALL roles externally to keep Linux RAM flat
  4. prefer_external flag → route external
  5. Default → load local GGUF (RAM-guarded)
  6. External failure → fall back to local GGUF if the role has one

The ConcurrencyTracker detects n8n bursts in real time. When ≥3 webhooks hit simultaneously, the engine flips to external-only routing so the Linux box's RAM stays flat — no OOM crashes.


Project structure

OrganicForge/
├── configs/
│   └── model_config.yaml      # the 2-SLM fleet + external providers + RAM guard (3000MB)
├── src/
│   ├── __init__.py
│   ├── engine.py              # InferenceEngine v2.2: dual-routing + burst detection + RAM GC
│   ├── searxng_client.py      # bulletproof graceful-failure SearXNG client
│   ├── app.py                 # FastAPI: /api/execute-workflow + /api/v2/n8n-trigger
│   └── modules/
│       ├── __init__.py
│       ├── seo.py             # SEO Auditor node (phi-4-mini + SearXNG context)
│       └── content.py         # Content Generator node (qwen + Pydantic schema)
├── requirements.txt
└── README.md

Quick start

1. Install dependencies

pip install -r requirements.txt

llama-cpp-python needs a C++ toolchain. For hardware-accelerated builds (CUDA / Metal / OpenBLAS), see: https://github.com/abetlen/llama-cpp-python#installation

2. Start the background services on the Linux box

# SearXNG (optional but recommended — graceful degradation if absent)
docker run -d --name searxng -p 8080:8080 searxng/searxng

# ChromaDB is auto-initialized by the engine on first query (persisted to .chroma/)
# n8n runs separately and calls into /api/v2/n8n-trigger

3. Start the external providers on the Windows host

Run kilocode and opencode on the Windows machine so their OpenAI-compatible servers are reachable at the IPs in configs/model_config.yaml. (If they're offline, the engine falls back to the local SLMs — the roles without a local GGUF will return empty output with a logged error.)

4. Run the API

python -m src.app
# or
uvicorn src.app:app --host 0.0.0.0 --port 8000

The first run downloads the 2 GGUF files from HuggingFace (~2.4GB + ~2.0GB, cached under ~/.cache/huggingface).


API

GET /api/health

Engine + SearXNG + ChromaDB + external-provider status snapshot.

GET /api/models

The configured local SLMs + external model registry + role index.

GET /api/modules

Available node types + their input schemas (for the visual canvas palette).

POST /api/execute-workflow

Run a visual node-canvas graph (topological sort + per-node execution):

{
  "nodes": [
    { "id": "n1", "type": "seo",     "data": { "url": "https://example.com", "target_keyword": "organic coffee" } },
    { "id": "n2", "type": "content", "data": { "topic": "organic coffee", "content_type": "social_post" } }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2" }
  ]
}

POST /api/v2/n8n-trigger ← production n8n webhook

The locked-down endpoint external n8n workflows POST into. Never raises — every exception is caught and returned as {ok: false, error} so a concurrent n8n loop can never crash the primary Python server thread.

POST /api/v2/n8n-trigger
{
  "kind": "generate_copy",
  "prompt": "Write a social post about {{topic}} for {{audience}}",
  "variables": { "topic": "organic coffee", "audience": "millennials" },
  "context_query": "organic coffee marketing 2025",
  "max_tokens": 512,
  "temperature": 0.6
}

Response:

{
  "ok": true,
  "kind": "generate_copy",
  "role": "creative_copywriting",
  "model": "llama-3.2-3b",
  "output": "☕ Your morning deserves better...",
  "error": null,
  "duration_ms": 2840,
  "concurrency": { "active": 1, "burst_threshold": 3, "in_burst": false },
  "variables_applied": 2
}

Task kinds → roles:

kind Role Routes to
audit_seo fast_logic phi-4-mini (local) OR kilocode:mimo (external)
generate_copy creative_copywriting Llama-3.2-3B (local) OR kilocode:laguna OR opencode:gemma-2-9b
generate_json json_structured kilocode:ling (external only — no local GGUF)
strategy_map strategic_reasoning kilocode:nemotron OR opencode:deepseek-r1-8b (external only)
custom fast_logic phi-4-mini (default)

Adding a new node

  1. Create src/modules/<name>.py with a run(input_data: dict, engine: InferenceEngine) -> dict function. Return {"ok": bool, "error": str|None, ...}.
  2. Register it in src/app.py's _NODE_REGISTRY + _NODE_INPUT_SCHEMAS.
  3. It now appears in /api/modules and is executable in the canvas.

Configuration

All knobs live in configs/model_config.yaml:

  • the 2 local SLMs (repo_id, filename, ram_mb, role)
  • the external providers (kilocode + opencode base URLs + model→role maps)
  • the RAM guard ceiling (target_total_mb: 3000)
  • the burst-mode threshold (burst_threshold: 3)
  • SearXNG endpoint + categories
  • ChromaDB persist dir + collection name
  • llama.cpp runtime (threads, GPU layers, context size)

Hybrid-RAG

Every prompt can be grounded in two context sources, blended into a preamble:

  • Local foundational knowledge — ChromaDB collection embedded with all-MiniLM-L6-v2. Offline, fast, grounded.
  • Real-time web context — pulled from the local SearXNG instance.

If SearXNG is offline, the SearXNGClient fails gracefully (never raises) and the engine proceeds with ChromaDB-only context.


License

MIT — see LICENSE.

About

Lightweight AI Model Design

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages