Guide
AI Analysis
Overview
Smart.Industrial.ai provides three analysis functions that work on the data the Industrial components already hold:
- summariseAlarms: reduces an alarm flood to the significant events.
- describeTrend: describes what a set of process values did over a period.
- explainSequence: turns a completed test run into a readable report.
The module is not a component. It is included in smart.industrial.js and is available as Smart.Industrial.ai, or through the source/modules/smart.industrial.ai.js module. It is built on Smart.Utilities.AIClient, the same client class the Grid's AI features use, and takes the same options.
Design
The data is reduced before it is sent. A shift of 1 Hz trend data is 28,800 samples per pen. Every function computes the statistics first and sends only the summary, which is faster, cheaper and gives the model a smaller and more useful input. It also means that much less of the plant's process data leaves the network. In the demo, 3.3 MB of trend data (28,800 rows) becomes a payload of about 850 bytes.
No request is sent without configuration. The client is unconfigured until the application provides a key, an endpoint or a transport, and every analysis function rejects instead of sending a request silently. With endpoint set to a service of your own, the data goes only there.
The two reducers, reduceAlarms and reduceTrend, are public and synchronous and can be used without a configured model. The alarm counts and the list of repeated alarms cover most of what an alarm rationalisation review needs.
Configuration
//A provider directly. Until a model is named, the model follows the provider:
//'claude-opus-5-5' for anthropic, 'gpt-4.1' for openai and azure, none for custom.
Smart.Industrial.ai.configure({ provider: 'anthropic', apiKey: '...' });
//Or your own service, so no key reaches the browser and no data leaves your network
Smart.Industrial.ai.configure({ endpoint: 'https://plant.internal/ai' });
//Or replace the transport entirely
Smart.Industrial.ai.configure({ sendRequest: (request) => myQueue.ask(request) });
configure accepts the options of Smart.Utilities.AIClient: provider (openai, the default, anthropic or custom), apiKey, model, endpoint, headers, timeout, retries and sendRequest. The module sends a temperature of 0.2 to OpenAI-format providers and none to anthropic, whose current models reject one; a temperature or model given to configure is sent as given. With endpoint set, the request is posted there in the wire format of provider: the OpenAI chat format by default, or { model, system, messages, prompt, temperature, maxTokens } with provider: 'custom'. A key given to configure is sent from the browser, so it is visible to anyone who can open the page; use an endpoint of your own for anything but a trial. The module keeps its own client, separate from the Grid's (Smart.AI), so configuring one does not configure the other. client() returns the client, for aborting a request or inspecting the configuration, and isConfigured() reports whether requests can be sent.
Alarms
const reduced = Smart.Industrial.ai.reduceAlarms(grid.alarms);
const summary = await Smart.Industrial.ai.summariseAlarms(grid.alarms, {
context: 'Continuous polymer line, one operator on shift.'
});
reduceAlarms takes alarm records in the format used by smart-alarm-grid and returns:
| Field | Meaning |
|---|---|
| total | How many alarms were in the list. |
| outstanding | Active and unacknowledged. |
| byPriority, byArea | Counts, keyed by priority and by area. |
| repeatOffenders | Up to ten tags that alarmed more than once, worst first. In almost every real flood a handful of tags produce most of the alarms, and naming them is more use than describing the flood. |
| spanSeconds | First to last timestamp, or null when no alarm carried one. |
| isFlood | True when the list averages more than ten alarms per ten minutes over spanSeconds, the ISA-18.2 flood threshold for one operator. It is an average over the whole span rather than a sliding ten-minute window, it treats the list as one operator's, and it is false when the span is unknown or zero. Decided here rather than by the model, so a standards judgement is not left to a language model. |
Trends
const reduced = Smart.Industrial.ai.reduceTrend(samples, chart.pens);
const description = await Smart.Industrial.ai.describeTrend(samples, chart.pens);
reduceTrend takes rows in the format used by smart-strip-chart or smart-chart and a pen list of { field, label, unit }, and returns samples and one entry per pen with label, unit, min, max, mean, stdDev, first, last, samples and two derived values:
- drift: the change over the period as a proportion of the range, where 1 is a steady rise across the whole range, -1 a steady fall and 0 no net change. It is measured between the first and the last tenth of the data rather than between two single readings, because process data is noisy. As a result a clean ramp reads about 0.9 rather than exactly 1.
- noiseRatio: the spread of the last third divided by the spread of the first third. A value above about 1.5 means the signal became noisier during the window, which is typical of a bearing or sensor problem and is not visible in a summary based on mean and range. It is null when there is too little data to compute it.
Missing values are treated as gaps. null, '', undefined and non-numeric values are skipped rather than counted as zero, which would lower the mean and report a minimum that was never measured.
Test runs
const text = await Smart.Industrial.ai.explainSequence(sequenceEditor.report(), {
context: 'PA-2200 audio power amplifier, serial 004817.'
});
explainSequence takes the object returned by the report() method of smart-sequence-editor. That object is already reduced to the verdict, the counts and one row per step, so it is sent as it is.
Errors
Every analysis function returns a promise. It rejects with a plain Error when the module is not configured, and otherwise with an AIError (the class is Smart.AI.Error, and error.name is 'AIError') whose code is one of not-configured, aborted, timeout, http, rate-limit, parse or network, so a misconfiguration can be told from a rate limit without parsing the message.
The model is instructed to use the tags and units exactly as given, not to invent measurements, tags or causes that are not in the data, and to say when the data does not support a conclusion. This is a prompt, not a guarantee: generated text should be treated as a draft for an engineer to review and sign, not as a record.
Demo
demos/industrial/ai-analysis runs all three functions on an alarm flood, a shift of trend data and a completed test run, and shows the exact payload each function would send. When no provider is configured, the demo installs a local writer so that the screen works without a key, and marks every answer as simulated.