Drupal is built on PHP, and it excels in delivering content between client, server, and edge. However, with highly intensive and CPU-heavy operations, it may fall short, especially with tasks such as parsing large files, processing media files (compression, transcription, vision), or with LLM interfaces.
WebAssembly (Wasm) is a binary instruction format that runs anywhere. It allows developers to run compiled code (Rust, C++, Go, etc.) inside a portable, secure sandbox at near-native speed.
Wasm runs in browsers, Node.js, and even at the edge (Cloudflare Workers), allowing it to take heavy operations off Drupal's back while keeping Drupal focused on content and workflow.
ONYX (Open Neural Network Exchange) is an open standard format for representing machine learning models, it allows trained models using frameworks like PyTorch or TensorFlow to be exported into a universal format. ONYX also runs directly in the browser, via WebAssembly.
Using all of those tools together can bring native AI integration to Drupal, directly from LLMs without relying on external APIs or AI Providers. This will keep the cost to $0, and ensure full privacy and security.
In this walkthrough, we will integrate a simple LLM model that predicts the emotional and social impact of a headline in Drupal form.
1. Prepare model files
The LLM model is hosted on HuggingFace, and to operate in Drupal, the model needs to be exported to ONYX format. This can be done by downloading the model and exporting it using:
optimum-cli export onnx \
--model 6u5haman/headliner \
--task text-classification \
./headliner-onnx
This will create a folder with several files, mv model.onnx to headliner.onnx for convenience, and place it in the module directory under /mymodule/models/headliner.onnx
This will enable the model to be accessible through a Drupal module.
2. Drupal library definition
We will load the JS interface through a Drupal library, headliner_ai.js will contain the inference logic, and drupalSettings will allow to pass the model URL from PHP to JS.
# mymodule.libraries.yml
headline_ai:
version: 1.x
js:
js/headline_ai.js: { type: module }
dependencies:
- core/drupal
- core/drupalSettings
3. Attach to Node Edit form
Attached the library to article edit for:
<?php
function mymodule_form_node_article_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
$form['#attached']['library'][] = 'mymodule/headline_ai';
$form['#attached']['drupalSettings']['headlineAI'] = [
'modelUrl' => '/models/headliner.onnx',
];
}
4. JavaScript inference
We will load ONYX model in the browser, encode the input headline as tensor, run inference using Wasm, and eventually display the result (impact/theme) below the headline field.
// js/headline_ai.js
import Drupal from "drupal";
import * as ort from "onnxruntime-web";
async function analyzeHeadline(modelUrl, text) {
// Load ONNX model
const session = await ort.InferenceSession.create(modelUrl, {
executionProviders: ["wasm"],
});
// Encode text input
const encoded = new TextEncoder().encode(text.toLowerCase());
const input = new ort.Tensor("int32", Int32Array.from(encoded), [1, encoded.length]);
// Run inference
const results = await session.run({ input_ids: input });
// Extract and results
const impact = results["impact"]?.data[0] || 0;
const theme = results["narrative"]?.data[0] || "General";
return { impact, theme };
}
/**
* Drupal behavior: attach to headline input.
*/
Drupal.behaviors.headlineAI = {
attach(context, settings) {
const cfg = settings.headlineAI || {};
const modelUrl = cfg.modelUrl || "/mymodule/models/headliner.onnx";
const headlineInput = context.querySelector('input[name="title[0][value]"]');
if (!headlineInput || headlineInput.dataset.aiBound) return;
headlineInput.dataset.aiBound = "1";
// output
const outputBox = document.createElement("div");
headlineInput.insertAdjacentElement("afterend", outputBox);
// when user types
headlineInput.addEventListener("input", async () => {
const { impact, theme } = await analyzeHeadline(modelUrl, headlineInput.value);
outputBox.innerHTML = `<strong>Impact:</strong> ${impact} | <strong>Narrative Cluster:</strong> ${theme}`;
});
}
};
By using WebAssembly (and WebGPU for more extensive operations) in Drupal with a robust caching strategy, organizations can unlock the unlimited resource of native AI capabilities.This workflow can be used to integrate much more complex, open, or larger LLMs directly into Drupal, in a native-performance and fully fault-tolerant environment.
Advanced LLM image tagging, text summarization, content suggestion, and more can become a native Drupal AI feature at zero cost and full privacy, without relying on proprietary services.