jev-video-classifier

n8n community node that classifies YouTube videos with the OpenRouter Decisions API (Jev) and applies calibrated tag thresholds and channel priors

Package Information

Released: this month
Downloads: 0 weekly / 0 monthly
Latest Version: 0.1.0
Author: Daniel Dolezal

Documentation

n8n-nodes-jev-video-classifier

n8n community node that classifies YouTube videos with the OpenRouter Decisions API
(model family Jev) and turns the raw probabilities into a decision using
calibrated tag thresholds, channel priors and a personal-interest rule.

It replaces a three-node chain (build payload → HTTP request → apply thresholds)
with one node that has retry, exponential backoff and a per-request timeout.

Install

In n8n: Settings → Community Nodes → Install → n8n-nodes-jev-video-classifier.

Self-hosted n8n with a mounted nodes folder:

npm install n8n-nodes-jev-video-classifier

Credentials

Option Credential Use when
OpenRouter API (Jev) (default) jevOpenRouterApi, ships with this package always available
OpenRouter API (built-in) openRouterApi from the n8n LangChain nodes you already store the key there

The key is never read from the environment; it stays in n8n's credential store.

Parameters

  • Config (required): the compact Jev runtime config as JSON. Accepts the whole
    Workflow - States row ({ "version": 1, "jev": { ... } }) or just the jev
    object. Typical expression:
    {{ $('Get Jev Value - Data').first().json.data }}
  • Taxonomy (required): taxonomy and prompt text as JSON. Use config/taxonomy.json
    or a data-table row/expression containing that file. This field owns veto,
    personal_interest.instructions, and tags.
  • Model: overrides jev.model
  • Options: transport/API settings: Endpoint, Description Limit, HTTP Referer, App Title, Concurrency, Retries, Timeout (ms)

Enable Continue on Fail to emit { output: null, error: "..." } for a failing
video instead of stopping the execution.

Config shape

{
  "model": "typesafe/jev-1.13",
  "thresholds": {
    "default": 0.6,
    "per_tag": { "linux": 0.42 },
    "min_tags": 1,
    "review_below_confidence": 0.8,
    "personal_interest_threshold": 0.15,
    "require_personal_interest": true,
    "non_trigger_tags": [],
    "min_tag_thresholds": {}
  },
  "channels": { "base_rate": 0.5, "strength": 0.6, "rates": { "some channel": 0.9 } }
}

Config only contains decision data: model, thresholds and channel priors.
Taxonomy/prompts live in Taxonomy; endpoint, timeout and retry settings live
in Options. Generate the compact runtime config with the jev-classifier CLI:

uv run jev-classifier export-state \
  --thresholds config/tags.json \
  --channels config/channels.json \
  --out out/workflow-state.json

Input

Each input item may be a raw YouTube API item or a flat row:

field fallbacks
id video_id
snippet.title title
snippet.description description (truncated to description_limit)
snippet.channelTitle channel_name, channel
snippet.tags tags (JSON string, array or "No Tags")

Output

{
  "video": { "id": "...", "title": "...", "channel": "...", "youtube_tags": [] },
  "output": {
    "interesting": true,
    "tags": [{ "tag": "Linux", "score": 93, "probability": 0.9312, "triggers_interest": true }],
    "veto": null,
    "needs_review": false,
    "personal_interest": 0.81,
    "veto_confidence": 0.99,
    "personal_interest_threshold": 0.15
  },
  "channel_shift": -0.14,
  "jev_probabilities": { "linux": 0.9312 },
  "raw_probabilities": "{\"linux\":0.9312}",
  "jev_usage": { "input_tokens": 812 },
  "jev_model": "typesafe/jev-1.13"
}

pairedItem is set, so item n of the output always belongs to item n of the input.

Retry behaviour

  • exponential backoff with full jitter, capped by the Retry Max Delay option
  • honours Retry-After
  • retries 408, 409, 425, 429, 5xx and network errors, never other 4xx
  • Concurrency requests in parallel, input order preserved

Development

npm install
npm run build          # dist/ for n8n
npm test               # build + node --test test

Only the community node is shipped. There is no Code-node bundle in this
package; use n8n community-node installation so credentials stay in n8n's
credential store.

License

MIT

Discussion