M-AIDA

M-AIDA: Meta-Analysis Intelligent Data Assistant

DOI version python frontend license

Research software for meta-analysis: semi-automated effect-size extraction from academic PDFs with a vendor-neutral large-language-model adapter, human-in-the-loop verification by the principal investigator, and an immutable data-lock workflow that exports a reproducible effect-size dataset for three-level meta-analytic regression.

Authors

Built to support the P6 (meta-analysis) component of the first author’s doctoral dissertation on the internationalization-performance relationship.

Scope: which kinds of literature review this serves. M-AIDA is an extraction-and-verification engine at the data-collection stage of PRISMA; it does not search the literature, does not screen records, and does not run the final statistical model. It serves a meta-analysis in full (its design target), the data-extraction stage of a systematic review (evidence-gated coding, recorded exclusion reasons, two independent coders), and small-scale evidence tables that ground the hypotheses of a proposal. It is of partial use for scoping reviews, marginal use for narrative reviews, and no use for bibliometric analysis, which is a different class of tool.

System Architecture

frontend (React 19, :3000)
    calls --> backend (FastAPI, :8765)
                 |-- extractor.py    vendor-neutral LLM parsing
                 |-- engines.py      provider adapter (LLM_PROVIDER / LLM_API_KEY / LLM_MODEL)
                 |-- models.py       Pydantic domain models
                 |-- notion_sync.py  optional Notion database sync

The language model is reached through a configurable adapter. Set LLM_PROVIDER, LLM_API_KEY and LLM_MODEL to your own provider; the software is not tied to any single vendor.

Quick Start

# 1. Configure environment
cp backend/.env.example backend/.env
# Edit backend/.env: LLM_PROVIDER, LLM_API_KEY, LLM_MODEL, NOTION_TOKEN, NOTION_DATABASE_ID

# 2. Start with Docker Compose
docker compose up

# 3. Open the app
open http://localhost:3000

Extracting, verifying, locking, and Notion sync all require an admin key (X-MAIDA-Admin-Key), so a visitor can never mutate studies through the API alone. MAIDA_ADMIN_KEY is unset above on purpose for a fast local start: the backend generates one and prints it to the console on every startup instead. Paste that value into the “Admin key” field in the app header once per browser (kept only in localStorage, never in the built JS). Set MAIDA_ADMIN_KEY in backend/.env for a key that survives a restart, and always set it before a real deployment - see Production deployment below.

One-command live demo (no Docker, no Node)

For demonstrations (e.g. a thesis defense) the repository ships a packaging harness that starts the real backend pre-seeded with real effect-size records from the dissertation’s locked P6 database and serves a dependency-free web console at the same port. No response is simulated; every action goes through the live API.

pip install -r backend/requirements.txt
python demo/run_defense.py
# Windows one-click alternative: demo\\start_defense_windows.bat
# macOS/Linux alternative: sh demo/start_defense_unix.sh
# open http://localhost:8765/  (interactive API docs at /docs)

Seeding rules and options (full-database seed, lock-all mode) are documented in demo/run_defense.py; a Vietnamese walkthrough for the defense session is in demo/HUONG_DAN_BAO_VE.md. The Defense App persists session changes locally, protects all mutations with a presenter PIN printed at startup, and can reset to the verified P6 seed. Live PDF extraction additionally requires LLM_API_KEY in backend/.env; without it the extraction endpoint returns an explicit 503 and verification, locking, filtering, reset, and CSV export continue to work offline.

Production deployment

To run the app for real (single host / VPS, prebuilt GHCR images, or a managed host) see DEPLOY.md: docker-compose.prod.yml, backend/.env.production.example, and a GHCR image-build workflow are provided. The staged plan toward a commercial SaaS (PostgreSQL, auth, billing) is in KE_HOACH_TRIEN_KHAI_APP_vi.md in the dissertation repository.

Development and tests

# Backend unit tests (effect-size conversions + confidence scheme)
cd backend
pip install -e ".[test]"
pytest -q

# Independent-validation analysis tests (synthetic fixtures only)
cd ..
python -m pytest -q validation/tests

# Frontend (Vite): dev server / production build
cd frontend
npm ci
npm run dev      # http://localhost:3000
npm run build    # outputs to build/

CI runs the backend test suite and the frontend Vite build on every change. Set VITE_API_URL (see frontend/.env.example) to point the client at a non-default backend URL.

The executable independent-validation package is in validation/, with the preregister-before-running design in VALIDATION_PROTOCOL.md. Its templates separate two human coders, the adjudicated gold standard, untouched machine proposals, and PI verification time. No product-accuracy claim is made until real frozen inputs and generated results are archived; synthetic CI fixtures only verify the metric calculations.

Execution status: the repository now includes a deterministic provisional sampling frame of 40 PRIMARY studies plus 10 RESERVE studies in validation/sampling/. Defense-demo studies and every study flagged is_estimated in the P6 database are excluded. The frame is not locked until full-text availability and non-use in M-AIDA development are confirmed for every PRIMARY study; the freeze command enforces both gates.

API Routes

Method Path Description Admin key?
POST /api/extract Base64 PDF body to an extracted effect size required
POST /api/extract/upload Multipart PDF upload to an extracted effect size required
GET /api/studies List studies (filter: icrv, dpl, verified, locked) -
GET /api/studies/{id} Single study detail -
PATCH /api/studies/{id}/verify PI field overrides and approval required
POST /api/studies/{id}/lock Irreversible PI data lock required
GET /api/studies/export/csv Export locked studies as CSV -
POST /api/notion/sync Push locked studies to Notion required
GET /api/health Health check and service configuration flags -

“Admin key” means the request must carry X-MAIDA-Admin-Key: <MAIDA_ADMIN_KEY> or the backend refuses it with 401, whatever the caller’s origin - see Security below. In demo mode (demo/run_defense.py) this check stands down in favour of that app’s own presenter-PIN middleware.

Extraction Workflow

Interactive diagram of the extract → verify → lock path: assets/diagrams/maida-workflow.html (open locally in a browser) (source: assets/diagrams/maida-workflow.workflow.json, rendered with Archify, MIT).

  1. Parse: PDF text is extracted with MuPDF and segmented into statistical regions. At most 40,000 characters of text are sent to the model (PDF_TEXT_LIMIT); when a paper is longer the record carries text_truncated = true, so an empty proposal can be told apart from a paper that reports no statistic.
  2. Identify: the LLM adapter proposes the focal internationalization-performance coefficient (not interactions or controls). Moderators (ICRV, DPL, cDAI) are left blank for the principal investigator to assign from external lookup tables.
  3. Convert: the canonical target is Pearson r. When only a derived statistic is reported, r is computed from t using Cohen (1988) with df = n − p − 1 taken from the model’s predictor count, or from a standardized beta using Peterson and Brown (2005): full formula r = 0.98β + 0.05λ, valid only for |β| ≤ 0.5; out-of-domain betas are rejected, never approximated. Each record carries metric_type, estimand_source, and source_controls, so beta-derived values enter sensitivity analysis only, and a three-level confidence score is attached.
  4. Evidence gate: a record is created only with page-and-quote evidence for both the statistic and the sample size (evidence_page/evidence_quote, n_evidence_page/n_evidence_quote). Missing evidence raises HTTP 422 and no record is stored: the system has no default or fallback output path for any input.
  5. Verify: the principal investigator reviews each field; any record with confidence below 0.70 is flagged for mandatory review. Corrections go through a whitelist of PI-editable fields (PI_EDITABLE_FIELDS, 7.2.0); a change to any primary statistic re-derives r, the variances (variance_r, variance_z), metric_type and the provenance fields through the same function live extraction uses. The machine’s proposal, its confidence score and the evidence quotes are never editable; human edits are logged in pi_edited_fields.
  6. Lock: an approved record that carries an effect size and its variance is permanently locked with a UTC timestamp and can no longer be edited; pi_locked and locked_at cannot be set by any other route. Only locked records enter the analysis export, which carries every field of the record.

Effect-size recoding and lock generations (analysis/)

The analysis/ package is the canonical, self-tested implementation of the conversion layer (effect_size.py with hand-computed unit tests, plus an R twin effect_size.R feeding the metafor pipeline). migrate_v8.py derives a new lock generation from a released dataset without ever editing it: v7.1.1 (DOI-pinned) stays immutable, every derived record carries a derived_from pointer, and excluded records keep a written reason (PRISMA-ready). Each run emits figures.json: the single source every display surface reads its headline numbers from. Policy details are in analysis/README.md.

Citation

If you use M-AIDA, please cite it (GitHub renders a “Cite this repository” button from CITATION.cff):

Do, T. H., and Phan, A. T. (2026). M-AIDA: Meta-Analysis Intelligent Data Assistant (Version 7.2.2) [Computer software]. Can Tho University. https://doi.org/10.5281/zenodo.21850575

Zenodo mints two kinds of identifier. The concept DOI 10.5281/zenodo.21850575 always resolves to the latest release; cite it for the software in general. A version DOI pins one release, for an exact reproducible build: 10.5281/zenodo.22920619 for v7.2.2 (tag v7.2.2, commit 8af4881, the current release), 10.5281/zenodo.22260059 for v7.2.1 (tag v7.2.1, commit d2ea8e3), 10.5281/zenodo.22259090 for v7.2.0 (tag v7.2.0, commit 3ff42c4, the first release after the 31 August 2026 code review), 10.5281/zenodo.21926336 for v7.1.1 and 10.5281/zenodo.21850576 for v7.1.2.

A separate Zenodo deposit of v7.1.1, made by hand on 9 July 2026 (concept 10.5281/zenodo.21282516, version 10.5281/zenodo.21282517), also remains published. It is the record cited by the first author’s dissertation and by the copyright-registration dossier, and it always resolves to v7.1.1. It is not part of the GitHub-archived series above, so it never advances to a newer release; new citations of the software as a whole should use 10.5281/zenodo.21850575.

Three Zenodo records minted on 3 September 2026 are superseded and must not be cited, because the GitHub releases behind them carried tags pointing at earlier commits than the release title claimed: 10.5281/zenodo.22258783 and 10.5281/zenodo.22258977 (from a release titled v.7.2.0, archiving the unpatched commit 3c8de32, and carrying the metadata version 7.1.1) and 10.5281/zenodo.22259684 (from a release titled v7.2.1, archiving the 7.2.0 commit 3ff42c4). The authors have asked Zenodo to withdraw them.

A fourth record, 10.5281/zenodo.22920581 (23 September 2026), is a duplicate of v7.2.2: the GitHub release was first published under the mistyped tag V7.2.2 and then re-tagged v7.2.2, and Zenodo archived both. It holds the same commit 8af4881, so its content is correct, but cite 10.5281/zenodo.22920619 so that every reference points at one record.

Authorship, license, and research-integrity note

Authors and copyright holders: Do Thuy Huong and Phan Anh Tu, School of Economics, Can Tho University. Copyright subsists automatically under Vietnamese law and the Berne Convention from the moment of creation; a Copyright Office of Viet Nam registration is being prepared with Can Tho University as a co-owner under the university’s intellectual-property regulations.

Role of computational assistance: M-AIDA uses a configurable language-model provider only to propose candidate effect sizes and statistical conversions from study text. It is a human-in-the-loop tool: every proposed value must be independently verified, corrected if needed, and permanently locked by the principal investigator before it enters the analysis database. The provider does not select studies, decide eligibility, run the meta-analysis, write interpretive content, or hold authorship or ownership over the software. Scientific responsibility remains with the named human authors.

Security: copy backend/.env.example to backend/.env and supply your own keys; never commit a real .env (it is git-ignored). In the recommended deployment (DEPLOY.md), nginx is the only published service and proxies every /api/ request straight to the backend; without a check there, any site visitor could call the same mutating routes the UI uses. Every extract/verify/lock/ Notion-sync request (7.2.2) is therefore gated on the X-MAIDA-Admin-Key header, checked against MAIDA_ADMIN_KEY (backend/main.py:admin_key_guard). Read-only routes (list/get studies, CSV export, health) stay public, since they serve the published, locked dataset this project exists to make transparent. Set MAIDA_ADMIN_KEY explicitly in production; left unset, the backend still starts but generates and logs a new key on every restart. This is single-shared-secret protection, appropriate for one PI’s own deployment - see Production hardening still on the roadmap in DEPLOY.md for the per-user auth planned before any multi-tenant or paid use.

License

M-AIDA is free/open-source software under the GNU Affero General Public License v3.0 (AGPL-3.0-only), see LICENSE. The AGPL’s Section 13 covers network use: running a modified version as a service requires publishing that version’s source.

Using M-AIDA under the AGPL requires no contact and no fee.

Commercial licensing is not currently available. Granting terms other than the AGPL requires holding, or being authorised by all co-holders to grant, the economic rights in the work. Those rights are not yet formally settled (see the next section), so no such grant can be made today. The position is stated in full in COMMERCIAL-LICENSE.md.

AGPL-3.0-only supersedes the earlier “M-AIDA Academic Source-Available License v1.0”, retired on 4 August 2026. Any document still carrying that name is out of date; LICENSE in this repository is the operative text.

Ownership, and why the Zenodo files are restricted

Economic rights in M-AIDA are held jointly by Can Tho University and the two authors, under Article 71 of the university’s science and technology management regulation (Decision 5152/QD-DHCT of 6 October 2023). The copyright registration is filed through the university and is still in process.

Because of that, the Zenodo deposits (the GitHub-archived series at 10.5281/zenodo.21850575 and the manual v7.1.1 deposit at 10.5281/zenodo.21282516) keep their files under restricted access while the records themselves, their metadata and their DOIs stay public and citable. This does not conflict with the AGPL: the AGPL governs what a recipient of the software may do with it, and obliges the authors to supply corresponding source to those recipients. It does not oblige anyone to publish files in any particular archive. The complete source is public in this repository, so the AGPL grant is fully effective today.

When the registration completes, opening the deposit is a decision for the joint owners, not for either author alone.