← Dokumentacija
LTLietuvių · In English

Blackoutly API — integracija su kitomis sistemomis

Blackoutly Enterprise. Instrukcija integratoriui ar administratoriui, jungiančiam Blackoutly prie kitos organizacijos sistemos: dokumentų valdymo, bylų, archyvo, el. pristatymo ar savo scenarijų. Toliau išorinė sistema — bet kuri tokia sistema.

1. Kaip veikia API

Blackoutly API — tai komandinė eilutė su JSON rezultatu, ne tinklo paslauga. HTTP / REST API nėra — sąmoningai. Programa niekada nesijungia prie tinklo ir neklauso jokio prievado (principas: dokumentai nepalieka kompiuterio). Integracija vyksta vietoje, per:

  1. Komandinę eilutę BlackoutlyCli.exe — išorinė sistema (jos tarnyba, suplanuota užduotis, scenarijus) ją paleidžia kaip procesą;
  2. failus aplankuose — įvesties dokumentai, peržiūros paketai (*.bo-review.json), rezultatai (*_bo_*.pdf);
  3. JSON išvestį (--json) ir grąžinimo kodus — išorinė sistema sužino, kas pavyko.

Žmogus visada patvirtina (programos principas). Todėl automatizuojama ne visa, o tai, kas aplink žmogų:

Programos API: išorinė sistema → prepare → darbuotojas A → darbuotojas B → apply → išorinė sistema

prepare sutaupo laiko (pasiūlymai paruošti iš anksto), apply išsaugo tik tai, ką antras asmuo patvirtino. Be išorinės sistemos tas pats daroma programos lange (B gali išsaugoti ir pats).

2. Reikalavimai

3. Komandos

BlackoutlyCli.exe prepare <failai ar aplankai>… [--review-dir APLANKAS] [--json] [--no-ocr] [--force]
BlackoutlyCli.exe apply   <failai ar aplankai>… [--review-dir APLANKAS] [-o REZULTATŲ_APLANKAS] [--json] [--no-ocr]
Parametras Reikšmė
<failai ar aplankai> PDF, JPG, TIFF failai; aplankas — visi jo tokie failai (be poaplankių, be *_bo_* rezultatų)
--review-dir Peržiūros paketų aplankas (numatyta: politika ReviewFolder, kitaip šalia failo)
-o, --output-dir Kur įrašyti rezultatus (numatyta: politika DefaultOutputDir, kitaip šalia originalo)
--json Rezultatas JSON masyvu į standartinę išvestį (be jo — eilutės žmogui)
--no-ocr Neatpažinti skenų (greičiau; skenuotuose puslapiuose pasiūlymų nebus)
--force prepare: perrašyti paketą, kurį žmogus jau peržiūri ar patvirtino (paprastai nenaudoti)

prepare — paruošti peržiūrai

Atidaro failus, randa pasiūlymus (visiems paketo failams kartu — pavardė, rasta viename, ieškoma visuose) ir kiekvienam sukuria peržiūros paketą būsenos draft. Darbuotojas, atidaręs tą failą programoje, mato pasiūlymus; pateikus — submitted. Failo, kurį žmogus jau peržiūri (submitted / approved), prepare neliečia.

Vienu kartu — ne daugiau kaip 50 failų (Enterprise riba; kiti praleidžiami su įspėjimu — paleiskite dar kartą), kiekvienas iki 500 psl.

apply — išsaugoti patvirtintus

Kiekvienam failui ieško paketo su ta pačia SHA-256 ir būsena approved, kurį paruošė ir patvirtino skirtingi asmenys. Tada: pasuka puslapius kaip peržiūroje, užjuodina patvirtintas vietas (su teisiniais pagrindais), sukuria naują PDF, patikrina rezultatą (patikrai radus problemų — failas neįrašomas, būsena blocked), įrašo audito įrašą (interface: cli, prepared_by, approved_by) ir pašalina paketą. Originalas niekada nekeičiamas.

apply nėra „išsaugoti vis tiek“ — patikros klaidų apeiti negalima.

4. Rezultatas

Grąžinimo kodai

Kodas prepare apply
0 visi failai paruošti arba praleisti visi failai išsaugoti
2 bent vienas failas su klaida bent vienas neišsaugotas (nepatvirtintas, sustabdytas patikros, klaida) arba failų nerasta
3 ne Enterprise licencija ne Enterprise licencija
1 netikėta programos klaida (tekstas — standartinėje klaidų išvestyje)

Kodas 2 nėra gedimas: JSON parodo, kuriuos failus apdoroti vėliau.

JSON (--json)

Masyvas, po vieną objektą kiekvienam failui. Laukas detail — paaiškinimas žmogui (lietuviškai), jo neanalizuokite programiškai — naudokite status.

prepare:

[
  {"file": "D:\\Integracija\\inbox\\ieskinys.pdf", "status": "prepared",
   "package": "\\\\serveris\\blackoutly\\review\\4f2a9c0e1b7d3a55.bo-review.json", "suggestions": 14},
  {"file": "D:\\Integracija\\inbox\\sutartis.pdf", "status": "skipped",
   "detail": "jau peržiūrimas ar patvirtintas (--force — perrašyti)"},
  {"file": "D:\\Integracija\\inbox\\pazeistas.pdf", "status": "error", "detail": "…"}
]
status Reikšmė
prepared Paketas sukurtas (package), pasiūlymų — suggestions
skipped Failą jau peržiūri ar patvirtino žmogus — nieko nedaryta
error Failo atidaryti nepavyko (slaptažodis, pažeistas, per daug puslapių)

apply:

[
  {"file": "D:\\Integracija\\inbox\\ieskinys.pdf", "status": "saved",
   "output": "D:\\Integracija\\outbox\\ieskinys_bo_20261018_142301.pdf", "redactions": 16,
   "output_sha256": "9b1c…"},
  {"file": "D:\\Integracija\\inbox\\sutartis.pdf", "status": "not_approved", "detail": "būsena: submitted"},
  {"file": "D:\\Integracija\\inbox\\skundas.pdf", "status": "blocked", "detail": "Paslėpta reikšmė vis dar matoma 2 puslapyje."}
]
status Reikšmė Ką daryti išorinei sistemai
saved Rezultatas output, patikrintas Paimti rezultatą, pažymėti bylą kaip anonimizuotą
not_approved Nėra patvirtinto paketo (dar peržiūrima) arba paruošė ir patvirtino tas pats asmuo Bandyti vėliau
blocked Patikra rado likusią paslėptą reikšmę — failas neįrašytas Grąžinti darbuotojui pataisyti
error Failo atidaryti nepavyko Pranešti administratoriui

output_sha256 sutampa su audito žurnalo įrašu — galima susieti išorinės sistemos įrašą su auditu nesaugant failų vardų.

5. Pavyzdžiai

5.1. PowerShell: suplanuota užduotis kas 10 minučių

# C:\Scripts\blackoutly-api.ps1 — paleidžia Task Scheduler tarnybos paskyra
$Cli    = "C:\Program Files\Blackoutly\BlackoutlyCli.exe"
$Inbox  = "\\serveris\blackoutly\inbox"      # išorinė sistema čia deda dokumentus anonimizuoti
$Review = "\\serveris\blackoutly\review"     # peržiūros paketai (tas pats, kas politika ReviewFolder)
$Outbox = "\\serveris\blackoutly\outbox"     # rezultatai išorinei sistemai
$Done   = "\\serveris\blackoutly\done"       # apdoroti originalai

[Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)

# 1) nauji failai -> pasiūlymai darbuotojams
$prepared = & $Cli prepare $Inbox --review-dir $Review --json | ConvertFrom-Json
if ($LASTEXITCODE -eq 3) { throw "Reikia Blackoutly Enterprise licencijos" }
$prepared | Where-Object status -eq "error" | ForEach-Object { Write-Warning "$($_.file): $($_.detail)" }

# 2) patvirtinti failai -> rezultatai
$applied = & $Cli apply $Inbox --review-dir $Review -o $Outbox --json | ConvertFrom-Json
foreach ($r in $applied) {
    switch ($r.status) {
        "saved"   { Move-Item $r.file $Done -Force; Write-Host "Anonimizuota: $($r.output)" }
        "blocked" { Write-Warning "Patikra sustabdė: $($r.file) — grąžinti darbuotojui" }
        default   { }   # not_approved: dar peržiūrima, kitą kartą
    }
}

Užduotis: Task Scheduler → Create Task → paleisti powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\blackoutly-api.ps1 kas 10 min., tarnybos paskyra, „Run whether user is logged on or not“. Kad du paleidimai nesutaptų — Settings → If the task is already running: Do not start a new instance.

5.2. Python

import json
import subprocess

CLI = r"C:\Program Files\Blackoutly\BlackoutlyCli.exe"


def blackoutly(command: str, *paths: str, review_dir: str, output_dir: str | None = None) -> list[dict]:
    args = [CLI, command, *paths, "--review-dir", review_dir, "--json"]
    if output_dir:
        args += ["-o", output_dir]
    proc = subprocess.run(args, capture_output=True, encoding="utf-8", timeout=3600)
    if proc.returncode == 3:
        raise RuntimeError("Blackoutly Enterprise licencija nerasta")
    if proc.returncode not in (0, 2):
        raise RuntimeError(proc.stderr)
    return json.loads(proc.stdout)


for row in blackoutly("apply", r"D:\Integracija\inbox", review_dir=r"\\srv\review", output_dir=r"D:\Integracija\outbox"):
    if row["status"] == "saved":
        print("OK", row["output"], row["output_sha256"])

5.3. C# (.NET)

using System.Diagnostics;
using System.Text.Json;

var psi = new ProcessStartInfo(@"C:\Program Files\Blackoutly\BlackoutlyCli.exe")
{
    RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false,
    StandardOutputEncoding = System.Text.Encoding.UTF8,
};
foreach (var a in new[] { "apply", @"D:\Integracija\inbox", "--review-dir", @"\\srv\review", "-o", @"D:\Integracija\outbox", "--json" })
    psi.ArgumentList.Add(a);

using var p = Process.Start(psi)!;
string json = p.StandardOutput.ReadToEnd();
p.WaitForExit();
if (p.ExitCode == 3) throw new InvalidOperationException("Reikia Blackoutly Enterprise licencijos");

foreach (var row in JsonDocument.Parse(json).RootElement.EnumerateArray())
    if (row.GetProperty("status").GetString() == "saved")
        Console.WriteLine(row.GetProperty("output").GetString());

5.4. Vienas failas iš komandinės eilutės (bandymui)

"C:\Program Files\Blackoutly\BlackoutlyCli.exe" prepare D:\Bandymas\ieskinys.pdf
"C:\Program Files\Blackoutly\BlackoutlyCli.exe" apply   D:\Bandymas\ieskinys.pdf -o D:\Bandymas\rezultatai

6. Peržiūros paketas (*.bo-review.json)

Failo vardas — pirmieji 16 failo SHA-256 simbolių: 4f2a9c0e1b7d3a55.bo-review.json. Paketas susietas su tiksliu failo turiniu: pakeistam failui (kita SHA-256) senas paketas netinka. Dokumento teksto pakete nėra — tik žymių vietos, todėl jį galima laikyti bendrame aplanke.

{
  "version": 1,
  "path": "\\\\serveris\\blackoutly\\inbox\\ieskinys.pdf",
  "file_name": "ieskinys.pdf",
  "sha256": "4f2a9c0e1b7d3a55…",
  "status": "approved",
  "profile": "court",
  "rotations": {"2": 90},
  "marks": [
    {"page": 0, "rects": [[72.0, 140.5, 188.2, 154.0]], "category": "name", "source": "auto",
     "state": "accepted", "confidence": "high", "key": "0:112:129:name", "basis": null},
    {"page": 1, "rects": [[60.0, 300.0, 300.0, 360.0]], "category": "manual", "source": "manual",
     "state": "accepted", "confidence": null, "key": null, "basis": "gdpr"}
  ],
  "seen": ["0:112:129:name"],
  "prepared_by": {"user": "petras", "computer": "PC-104", "ts": "2026-10-18T10:02:11+03:00"},
  "approved_by": {"user": "ona", "computer": "PC-117", "ts": "2026-10-18T13:45:40+03:00"},
  "submitted_marks": [ … ]
}
Laukas Reikšmė
status draft (paruošė prepare), submitted (pateikė darbuotojas), approved (patvirtino kitas)
rotations Puslapio Nr. (nuo 0) → pasukimas laipsniais pagal laikrodžio rodyklę
marks[].rects Stačiakampiai taškais (1/72 colio), pradžia — viršutinis kairysis pasukto puslapio kampas: x0, y0, x1, y1
marks[].state pending (neperžiūrėta — nebus paslėpta), accepted (bus paslėpta), rejected
marks[].category name, personal_code, address… arba organizacijos org:<id>; manual — pažymėta rankomis
marks[].basis Teisinio pagrindo ID iš taisyklių failo; null — pagal kategoriją, "-" — be pagrindo
prepared_by, approved_by Windows naudotojas, kompiuteris, laikas
submitted_marks Žymės, kokias pateikė A (kaip marks) — matyti, ar B jas keitė

Paketo nekurkite ir nekeiskite patys savo sistema: formatas gali keistis naujose versijose (version), o rankomis pakeistas approved_by apeitų keturių akių principą — tai pažeistų organizacijos tvarką (kas iš tikrųjų išsaugojo, visada matyti audito žurnale). Žymes išorinė sistema gali tik skaityti (pvz. kiek paslėpta), o kurti — per programą.

7. Saugumas ir patarimai

Kitos komandos (info, suggest, redact) skirtos kūrėjams ir diagnostikai; integracijai jų nenaudokite — redact --auto išsaugo be žmogaus patvirtinimo.