Overview
This Node-RED flow automatically extracts keywords from a Censhare image asset using the Censhare AI Private server (e.g. vision model “gemma4:latest”), along with a relevance score for each keyword, and writes them back into the asset as linked keyword references in Censhare. It is a single-pass flow as it handles multiple values with relevance scores in one operation.
How the Flow Works
The flow runs sequentially in the following stages:
-
Trigger - An Inject node fires with a Censhare asset-id
-
Image Fetch - The asset thumbnail URL is retrieved from Censhare
-
Prompt Build - A multimodal prompt is constructed instructing the LLM to extract up to 3 keywords with relevance scores (0–100)
-
LLM Analysis - The image is sent to Censhare AI Private server using a vision model like “gemma4:latest”; the model returns a structured array of keyword/relevance pairs
-
Payload Build - The function node builds two sets of Censhare payloads: one to create/register the keyword assets, and one to link them to the original asset with relevance scores
-
Asset Update - All keyword assets and their links to the target asset are written to Censhare in a single create-update-asset call
Prerequisites
|
Requirement |
Details |
|
Censhare AI Private Server |
Censhare AI Private Server Size S/M/L |
|
Node-RED Modules |
|
|
Environment variables |
|
|
Censhare Asset |
A valid asset with a thumbnail or preview storage item |
|
AI Model |
A vision model like “gemma4:latest” must be available on the configured AI server |
Sample flow
Sample LLM Output
Input: Image of a globe made of puzzle pieces with letters
{
"keywords": [
{ "keyword": "Globe", "relevance": 95 },
{ "keyword": "Puzzle", "relevance": 85 },
{ "keyword": "Letters", "relevance": 75 }
]
}
Each keyword is then registered as a Censhare asset and linked to the original image asset with its relevance score.
Technical Implementation
The function node performs 3 operations in a single payload sent to Censhare:
Step 1 - Keyword Asset Creation: For each keyword, a keyword asset is built with type, display name, and a unique resource key:
{
"uniqueKey": { "resourceKey": "demoai:keyword." + item.keyword },
"assetProperties": [
{ "traitName": "type", "propertyName": "type", "values": [{ "value": "module.keyword." }] },
{ "traitName": "display", "propertyName": "name", "values": [{ "value": item.keyword }] },
{ "traitName": "resource_asset", "propertyName": "key", "values": [{ "value": "demoai:keyword." + item.keyword }] }
]
}
Step 2 - Keyword Reference with Relevance: Each keyword is linked to the target asset with its relevance score:
{
"operation": "CREATE",
"valueId": -1,
"value": "demoai:keyword.Globe",
"relevance": 95
}
Step 3 - Combined Censhare Payload: All keyword assets and the target asset update are merged into a single payload:
{
"assets": [
{ "assetProperties": [ ...keyword asset 1... ] },
{ "assetProperties": [ ...keyword asset 2... ] },
{ "assetProperties": [ ...keyword asset 3... ] },
{
"uniqueKey": { "assetId": 229469 },
"assetProperties": [
{
"traitName": "category",
"propertyName": "keywordRef",
"values": [
{ "operation": "CREATE", "valueId": -1, "value": "demoai:keyword.Globe", "relevance": 95 },
{ "operation": "CREATE", "valueId": -1, "value": "demoai:keyword.Puzzle", "relevance": 85 },
{ "operation": "CREATE", "valueId": -1, "value": "demoai:keyword.Letters", "relevance": 75 }
]
}
]
}
]
}
Error Handling
The function node validates both msg.payload.keywords (must be a non-empty array) and msg.assetId before building the payload, halting gracefully with descriptive error messages if either is missing or invalid. The create-update-asset node has dedicated success and error debug nodes on its two outputs to ease error handling.
Notes
-
The flow is currently configured for asset ID. Update the Inject node to process a different asset
-
The prompt limits extraction to a maximum of 3 keywords: this can be adjusted in the prompt for keywords with relevance function node
-
Keyword assets are uniquely identified by the key format demoai:keyword.<keyword>. If the same keyword is extracted again for a different asset, the existing keyword asset is reused rather than duplicated