lumnik. / scénarios Tous les scénarios · English

Rapport HPLC: l'impureté hors limite, lue dans l'export de l'instrument

Objectif Lire les rapports d'injection qu'exporte un HPLC, unités collées et virgules décimales, et être prévenu quand une impureté dépasse sa spécification.

Le logiciel d'acquisition d'un HPLC exporte un rapport par injection: UTF-16, un bloc d'en-tête, puis les pics.

line
BOM:ff fe
line
Report;Area Percent / External Standard
line
Sample Name;LOT 26-0451 Assay
line
Sample Info;Paracétamol 500 mg, comprimé
line
Injection Date;05/11/2026 09:13:32
line
Instrument;HPLC-02
line
Method;ASSAY-PARA-V3.M
line
Peak;RetTime;Name;Area;Amount
line
1;2,315min;Impurity A;1 231,1mAU*s;0,08%
line
2;4,872min;Paracetamol;1 535 987,4mAU*s;99,81%
line
3;6,103min;Impurity B;1 692,8mAU*s;0,11%

preuves: replay.log, report-0451.txt, peaks-0451.txt, count-read.txt, impurities.txt, inbox-drop.json · transform v1

manifests/10-injection-reports.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-chrom-a  connector_type: csv-file  scopes: [qc-hplc-a]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/chromatograph-report/a/*.csv   # the folder the acquisition software exports to  parser:    lines: true                    # a report, not a table: a header block, then the peaks  after_process: none  mapping:    cell:      - regex-extract: { column: line, pattern: "^([^;]+);", groups: { 1: field } }      # the header block: one key;value per line      - regex-extract: { column: line, pattern: "^Sample Name;(LOT \\S+)", groups: { 1: sample } }      - regex-extract: { column: line, pattern: "^Injection Date;(.+)$", groups: { 1: injected_at } }      - regex-extract: { column: line, pattern: "^Instrument;(.+)$", groups: { 1: instrument } }      - regex-extract: { column: line, pattern: "^Method;(.+)$", groups: { 1: method } }      # a peak: the value and its glued unit, cut apart      - regex-extract:          column: line          pattern: "^(\\d+);([\\d ,]+)(min);([^;]+);([\\d ,]+)(mAU\\*s);([\\d ,]+)(%)$"          groups: { 1: peak, 2: rt, 3: rt_unit, 4: peak_name, 5: area, 6: area_unit, 7: amount_pct, 8: amount_unit }      # the report's header, on each of its peaks; a new report starts empty      - fill-down: { columns: [sample, injected_at, instrument, method], reset-when: { column: field, in: [Report] } }      - parse-number: { column: rt, decimal-separator: "," }      - parse-number: { column: area, decimal-separator: "," }      - parse-number: { column: amount_pct, decimal-separator: "," }      - parse-date: { column: injected_at, formats: ["dd/MM/yyyy HH:mm:ss"] }
manifests/20-impurity-over-limit.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-chrom-impurity-aspec:  scope: qc-hplc-a  on: { event: data.row.changed, table: connector.t_scenario_chrom_a }  when:    - peak_name~Impurity    - amount_pct>0.15                # the specification's limit for a specified impurity  emit:    type: decision.impurity-over-limit-a    message: "{sample}: {peak_name} at {amount_pct} % (limit 0.15 %), {instrument}, injected {injected_at}"    key: sample
$ lm connector run scenario-chrom-a
run scheduled: 526b41ae-87dd-4e89-adf3-e1cbd5c90596

$ lm run get 526b41ae-87dd-4e89-adf3-e1cbd5c90596
ID        CONNECTOR         ENDPOINT  STATUS     IN  OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
526b41ae  scenario-chrom-a  default   Completed  60  60   0        0             2026-11-06 17:04  2026-11-06 17:04  yes
• 1 file(s) unchanged since they were last read — not read again

$ lm inbox --process scenario-chrom-impurity-a
ID     WHEN      PROCESS                    MESSAGE                                                                                   ENTITY_KEY
24660  just now  scenario-chrom-impurity-a  LOT 26-0459: Impurity B at 0.21 % (limit 0.15 %), HPLC-02, injected 2026-11-06T08:57:32Z  LOT 26-0459

Limites

  • La table garde chaque ligne du rapport, en-tête compris: une règle lit les pics par leurs colonnes.
  • Une limite pour toutes les impuretés: une limite par impureté, c'est un Process par impureté.
  • Le regex attend ces trois unités; une autre unité laisse la ligne non découpée, et la règle ne la voit pas.
  • Lots, pics et teneurs synthétiques.

Laboratoire · HPLC

Les résultats dorment dans les rapports de l'instrument.

Un fichier par injection, fait pour être imprimé.

UTF-16, 1 532 117,2mAU*s, 0,21%

Le problème

LOT 26-0459: impureté B à 0,21 %.

  • La limite est 0,15 %.
  • Le rapport se lit à l'œil, quand il est lu.

Ce qui n'est pas modifié

Le logiciel d'acquisition reste tel quel.

  • Son propre export, dans son propre dossier.
  • Aucun script, aucune conversion à la main.

Ce qu'il a fallu écrire

pattern: "([\\d ,]+)(%)"
fill-down: { reset-when: Report }

Un regex par type de ligne, un fill-down.

  • L'unité dans sa propre colonne.
  • Un Process: impureté au-delà de 0,15 %.

Le résultat

Une décision, LOT 26-0459.

  • LOT 26-0461 est pile à 0,15 %: pas au-delà.
  • 36 pics, 0 erreur de cellule.

Essayer

Le scénario se rejoue en local.

Chaque étape est publiée avec sa sortie.

Ce scénario tourne sur lumnik Open, gratuit et open source.

Essayer lumnik Open →