Skip to content
Get Started

Data

How Standardization Works

How structured readings become coded, unit-normalized, queryable data.

Health data arrives messy — “血糖(空腹)”, “FBG”, “Glucose, fasting” all name the same indicator, and the units vary just as much. Mirobody standardizes every structured reading written through POST /v1/data or stored by POST /v1/standardize, so the agent and your queries see one coherent, coded dataset.

POST /v1/files is a separate storage and text-extraction surface; uploading a file standardizes its report values into structured readings automatically. /v1/standardize is the explicit path for that same extraction — use it to inspect the result (dry-run), or to standardize text / file_key sources on demand.

Both a document and a structured record enter the same pipeline:

  1. Read the source PDF / image → text (OCR); Excel → rows.
  2. Pull out readings Find each {indicator, value, unit, date}. Documents only — a /v1/data record is already structured and skips straight to coding.
  3. Code the indicator Match the name to a LOINC code. With no confident match, loinc_code stays null — never a wrong code.
  4. Normalize the unit Fold the unit spelling to one UCUM form and parse the value to a number: "mg/dl"mg/dL.
  5. Store as one series One row per reading on the Subject's timeline, queryable by indicator, code and date.

The important part is step 3: codes are matched, never invented. A model is great at reading a document but shouldn’t be trusted to recite a code system — a wrong LOINC code is worse than none. So when the match isn’t confident, Mirobody keeps the raw name and leaves loinc_code null rather than guess.

When self-hosting, this pipeline covers structured readings: the engine’s provider channel and its on-device batch import share one normalized write, while file extraction writes straight to the store and keeps the report’s own indicator names for semantic search to reconcile. See Data Flow.

What you send to /v1/data (or what /v1/standardize reads from a report) vs. what the structured store holds:

Before (as written)After (standardized)
Indicator"血糖(空腹)" / "FBG" / "Glucose, fasting"loinc_code: "1558-6", canonical_name: "Fasting glucose [Mass/volume] in Serum or Plasma"
Value"97 mg/dL" (one string)value: "97" (raw value, no unit), parsed_value: "97", parsed_unit: "mg/dL" (UCUM)
Unit spelling"mg/dl", "MG/DL", "mg/dL""mg/dL" (one UCUM form)
Interopfree textLOINC code + UCUM unit, the vocabularies FHIR itself uses
Originalkept: value holds the raw value as written (e.g. 97, no unit appended — the unit rides in parsed_unit); raw names/units preserved

Three spellings of the same test become one series — trend queries, the agent’s data tools, and your own analytics all see it as one indicator.

SurfaceWhat appears
POST /v1/dataResponse counts standardized alongside ingested.
GET /v1/dataEvery row carries parsed_value / parsed_unit / loinc_code / canonical_name, plus the reference range and abnormal flag when the source carried them.
POST /v1/standardizeThe whole pipeline as a synchronous call — dry-run by default, so you can inspect standardization before committing a write.
The agentGrounded answers query the standardized series — which is why “how’s my glucose?” finds records written as “FBG”.

Cookbook: one call, report → structured data

Section titled “Cookbook: one call, report → structured data”
Terminal window
# Inspect first (nothing persisted) …
curl https://api.mirobody.ai/v1/standardize \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-F "user=alice" -F "file=@lab_report.pdf"
# … then commit the same extraction
curl https://api.mirobody.ai/v1/standardize \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-F "user=alice" -F "file=@lab_report.pdf" \
-F "store=true" -F "retention=permanent"

See Standardize a report for the full row shape (indicator_raw, loinc_code, confidence, …).