Regex → OCR → pravidlá: architektúra flowu, ktorý triedi 3 000 faktúr mesačne
Flow v Microsoft Power Automate, ktorý pre BK a.s. triedi približne 3 000 faktúr mesačne, nestojí na jednom „inteligentnom“ kroku, ale na troch vrstvách rozhodovania zoradených od najlacnejšej po najdrahšiu: porovnanie vzorov v texte e-mailu, OCR nad PDF prílohami cez Azure Document Intelligence a záložné pravidlá v SharePoint zozname. Výsledkom je 70 % faktúr doručených bez zásahu človeka a 99 % úspešnosť rozpoznávania.
V prvom diele série sme ukázali, prečo BK ušetrilo 90 hodín mesačne. Tento diel je pre tých, ktorí chcú vedieť, ako je flow postavený: aké komponenty používa, kde sú háčiky Power Automate a čo by sme dnes urobili inak.
Architektúra v skratke
| Vrstva | Čo robí | Technológia | Kedy sa spúšťa |
|---|---|---|---|
| 0 – Trigger | Nový e-mail v zdieľanej účtovnej schránke | Power Automate, Office 365 Outlook konektor | každý e-mail |
| 1 – Text | Nájde číslo objednávky v predmete alebo tele e-mailu | Power Automate expressions | vždy |
| 2 – OCR | Prečíta číslo objednávky, číslo faktúry a sumu z PDF | Azure Function + Azure Document Intelligence | ak vrstva 1 nič nenašla |
| 3 – Pravidlá | Smeruje podľa odosielateľa, predmetu alebo obsahu | SharePoint zoznam | ak vrstvy 1 a 2 nič nenašli |
| Spoločné | Dotaz do objednávkového systému, doručenie, log | HTTP konektor, Outlook, SharePoint, Power BI | po každom rozhodnutí |
Prečo tri vrstvy a nie jeden AI model
Prvá myšlienka pri takejto úlohe býva „pošlime všetko do AI, nech rozhodne“. Zavrhli sme ju z troch dôvodov.
- Náklady. Každé volanie OCR alebo jazykového modelu stojí peniaze. Pri 3 000 faktúrach mesačne je rozdiel medzi „vždy“ a „len keď treba“ výrazný. Expression v Power Automate stojí nulu.
- Determinizmus. Účtovníctvo potrebuje vedieť, prečo faktúra skončila u konkrétneho človeka. „V predmete bolo číslo objednávky X, systém vrátil meno Y“ sa vysvetľuje ľahko. Pravdepodobnostný výstup modelu nie.
- Správa bez IT. Podmienkou klienta bolo, aby si účtovný tím vedel meniť smerovanie sám. SharePoint zoznam vie upraviť každý; prompt alebo trénovací dataset nie.
Vrstvy sú preto zoradené od najlacnejšej a najspoľahlivejšej po najdrahšiu. Keď jedna vrstva nájde jednoznačnú odpoveď, ďalšie sa nespúšťajú. AI klasifikácia má v tomto návrhu miesto až ako štvrtá vrstva pre zvyšok, ktorý dnes rieši človek – a presne tam ju plánujeme nasadiť.
Architektúra a tok dát

Každý e-mail prejde maximálne tromi rozhodnutiami; každé skončí buď doručením, alebo označením na ručné spracovanie, a vždy záznamom v logu.
Komponenty a ich úloha:
- Power Automate (cloud flow) – orchestrácia. Trigger na zdieľanú schránku, vetvenie, volanie služieb, preposielanie, zápis do logu.
- Azure Function (Python) – všetko, čo Power Automate nevie alebo robí draho: skutočný regex, spracovanie PDF, volanie Document Intelligence, spracovanie viacerých faktúr v jednom súbore.
- Azure Document Intelligence – OCR a extrakcia polí z faktúr.
- Interný objednávkový systém BK – zdroj pravdy pre „kto je zodpovedný za objednávku“, volaný cez HTTP.
- SharePoint – dva zoznamy: pravidlá smerovania (spravuje biznis) a log spracovania (zapisuje flow).
- Power BI – report nad logom.
Flow beží v tenante klienta pod servisným účtom, nie pod osobným kontom konzultanta. Zdá sa to samozrejmé, ale je to najčastejšia príčina, prečo automatizácie „záhadne“ prestanú fungovať po odchode človeka.
Vrstva 1: číslo objednávky v texte e-mailu
Prvá vrstva rieši najjednoduchší a najpočetnejší prípad: dodávateľ napíše číslo objednávky do predmetu alebo tela e-mailu. Čísla objednávok BK majú pevný formát – písmenový prefix a pevný počet číslic – čo je ideálny prípad pre porovnanie vzorov.
Power Automate nemá regex
To je prvý háčik. V expressions nie je žiadna funkcia match() ani regex(). Máte indexOf, substring, contains, split a startsWith. Pri pevnom formáte to stačí:
if(
and(
greater(indexOf(variables('text'), 'PREFIX'), -1),
greaterOrEquals(
length(variables('text')),
add(indexOf(variables('text'), 'PREFIX'), 8)
)
),
substring(variables('text'), indexOf(variables('text'), 'PREFIX'), 8),
''
)
Dve veci, ktoré vás v produkcii dobehnú, ak ich nevyriešite:
substringpadá pri prekročení dĺžky. Ak je prefix na konci reťazca a za ním už nie je 6 číslic, celý flow skončí chybou. Preto kontrolagreaterOrEquals(length(...))pred každýmsubstring.- Null v predmete. E-mail bez predmetu nie je prázdny reťazec, ale
null, aindexOf(null, ...)zlyhá. Všetko, čo prichádza z triggera, obalte docoalesce(triggerOutputs()?['body/subject'], '').
Telo e-mailu najprv prevedieme z HTML na čistý text (akcia Html to text), inak sa číslo objednávky môže skrývať medzi tagmi a indexOf ho nájde na nesprávnom mieste alebo vôbec.
Dotaz do objednávkového systému
Nájdené číslo ide cez HTTP akciu do interného objednávkového systému BK, ktorý vráti meno zodpovedného účtovníka a názov projektu. Odpoveď spracuje Parse JSON. Schému generujeme zo vzorky, ale vždy ju ručne skontrolujeme: ak vo vzorke príde číslo ako reťazec, schéma ho zafixuje ako string a prvá odpoveď s integerom flow zhodí. Polia, ktoré môžu chýbať, sú v schéme označené ako ["string", "null"].
Ak systém číslo nepozná (preklep dodávateľa, stará objednávka), vrstva 1 končí bez výsledku a flow pokračuje vrstvou 2.
Vrstva 2: OCR nad PDF prílohami
Väčšina dodávateľov číslo objednávky do e-mailu nenapíše – je len vo faktúre. Flow preto vyfiltruje PDF prílohy a pošle ich do Azure Function.
Prečo Azure Function a nie priamo konektor
Document Intelligence má v Power Automate vlastný konektor, ale používame ho až vo funkcii. Dôvody:
- Náklady. Veľká časť faktúr má textovú vrstvu – nie sú to skeny. Funkcia najprv skúsi vytiahnuť text knižnicou
pdfplumberzadarmo a Document Intelligence volá len pre strany, kde text chýba alebo je krátky (nečitateľný sken, obrázok). - Skutočný regex. V Pythone sú vzory čísel objednávok jeden
re.findall. V Power Automate by to bol strom podmienok. - Viac faktúr v jednom PDF. Dodávatelia bežne pošlú jeden súbor s piatimi faktúrami. Funkcia vráti pole výsledkov, nie jeden.
def extract_text(pdf_bytes: bytes) -> str:
pages = []
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
for page in pdf.pages:
text = page.extract_text() or ""
if len(text.strip()) > 50:
pages.append(text)
else:
pages.append(ocr_page(page)) # Azure Document Intelligence
return "\n".join(pages)
Funkcia vracia pre každú nájdenú faktúru číslo objednávky, číslo faktúry a sumu. Flow potom pre každé číslo objednávky zopakuje dotaz do objednávkového systému z vrstvy 1.
Háčiky pri prílohách
- Base64 je už hotové.
contentBytesz Outlook triggera je už zakódovaný obsah. Ak ho preženiete ešte raz cezbase64(), funkcia dostane nezmysel a OCR „záhadne“ nenájde nič. - Filtrujte podľa prípony, nie content-type. Niektorí klienti posielajú PDF s
application/octet-stream. Spoľahlivé jeendsWith(toLower(name), '.pdf'). - Vložené obrázky v podpise sú tiež prílohy. Bez filtra ich pošlete do OCR a platíte za logá dodávateľov.
- Timeout. HTTP akcia v Power Automate čaká štandardne do 2 minút. Pri 20-stranovom skene to nemusí stačiť; funkcia je preto asynchrónna a flow používa Retry policy s exponenciálnym odstupom.
Úspešnosť rozpoznávania čísel z textu a PDF je v produkcii 99 %. Zvyšné percento sú prevážne fotografie faktúr z mobilu a dokumenty, kde číslo objednávky jednoducho nie je.
Vrstva 3: pravidlá, ktoré si spravuje biznis
Tretia vrstva zachytáva e-maily bez čísla objednávky: pravidelné faktúry za energie, nájmy, služby, alebo dodávateľov, ktorí číslo zo zásady neuvádzajú. Tu nie je čo rozpoznávať; je čo vedieť. A to vie účtovný tím, nie my.
Pravidlá žijú v SharePoint zozname s týmito stĺpcami:
| Stĺpec | Typ | Príklad |
|---|---|---|
| Odosielateľ obsahuje | text | @dodavatel-energie.sk |
| Predmet obsahuje | text | Vyúčtovanie |
| Obsah PDF obsahuje | text | Odberné miesto 123 |
| Príjemca | osoba | účtovník |
| Projekt | text | názov strediska |
| Priorita | číslo | 10 |
| Aktívne | áno/nie | áno |
Flow načíta aktívne pravidlá zoradené podľa priority a vyhodnotí ich postupne; prvá zhoda vyhráva. Prázdna podmienka sa ignoruje, takže pravidlo môže byť len „odosielateľ“ alebo kombinácia všetkých troch.
Tri detaily, ktoré rozhodli o tom, či to tím bude používať
- Stĺpec Priorita. Bez neho sa pri dvoch zhodách rozhoduje náhodne (presnejšie: podľa poradia ID), čo tím rýchlo prestane dôverovať.
- Stĺpec Aktívne namiesto mazania. Pravidlo sa dá vypnúť a vrátiť. Nič sa nestratí.
- Príjemca ako stĺpec typu Osoba, nie text. E-mail vyberá flow z profilu, takže preklep v adrese nie je možný. Pozor pri čítaní: lookup a person stĺpce vracajú objekt, nie hodnotu – e-mail je v
items('Apply_to_each')?['Prijemca']?['Email'].
Zmena pravidla sa prejaví pri ďalšom e-maile, bez zásahu do flow a bez nasadzovania. Od spustenia v marci 2026 pridal účtovný tím desiatky pravidiel sám.
Logovanie: každý e-mail má záznam
Posledný krok každej vetvy je zápis do SharePoint zoznamu Log spracovania. Záznam obsahuje:
- identifikátor e-mailu (Internet Message ID) a čas prijatia,
- odosielateľa a predmet,
- metódu rozhodnutia:
text,ocr,pravidlo,rucne, - nájdené číslo objednávky, číslo faktúry a sumu (ak sú),
- príjemcu a projekt,
- stav (
dorucene,chyba,rucne) a prípadnú chybovú správu, - odkaz na beh flowu.
Posledný bod šetrí najviac času pri podpore. Odkaz na konkrétny beh sa dá zložiť priamo vo flowe:
concat(
'https://make.powerautomate.com/manage/environments/',
workflow()?['tags']?['environmentName'],
'/flows/', workflow()?['name'],
'/runs/', workflow()?['run']?['name']
)
Keď účtovník napíše „faktúra od XY mi neprišla“, nájdeme záznam podľa odosielateľa a jedným klikom sme v behu, ktorý ju spracoval.
Chyby sa logujú, nie strácajú
Celé spracovanie je v Scope bloku; za ním nasleduje druhý Scope nastavený na Run after: has failed, has timed out. Ten zapíše do logu stav chyba s textom z result('Scope_spracovanie') a e-mail označí kategóriou na ručné spracovanie. Bez tejto konštrukcie by neúspešný beh skončil červenou ikonou v histórii flowu, ktorú nikto nesleduje, a faktúra by zostala v schránke.
Power BI nad logom
Report číta zoznam priamo cez SharePoint konektor a ukazuje:
- podiel metód rozhodnutia v čase (koľko % išlo cez text, OCR, pravidlá, ručne),
- úspešnosť OCR a priemerný čas spracovania,
- dodávateľov s najvyšším podielom ručného spracovania – presne tam sa oplatí pridať pravidlo alebo požiadať dodávateľa, aby uvádzal číslo objednávky.
Práve tento posledný pohľad posunul podiel automatizácie z počiatočných hodnôt na dnešných 70 % – nie zmenou kódu, ale pridaním pravidiel a dohodou s pár dodávateľmi.
Päť poučení z produkcie
- Premenné inicializujte len na koreni flowu. Initialize variable nefunguje vo vetve podmienky, v Apply to each ani v Scope. Všetky premenné vytvárame hneď za triggerom s prázdnou hodnotou a vo vetvách používame len Set variable. Znie to triviálne, ale je to najčastejší dôvod, prečo sa flow nedá uložiť po refaktoringu.
- Vypnite súbežnosť tam, kde píšete do premenných. Apply to each beží štandardne paralelne. Ak v ňom nastavujete premennú (napr. „nájdené číslo“), dve iterácie sa prepíšu. Buď Concurrency control na 1, alebo zbierajte výsledky cez Append to array.
- Správne poradie vrstiev sa ukáže až na dátach. Pred nasadením sme flow pustili nad mesiacom historických e-mailov v režime „len loguj, neposielaj“. Ukázalo to, ktoré vzory čísel objednávok chýbajú, a pridalo pár percent k automatizácii ešte pred spustením.
- Každý externý dotaz musí mať plán B. Objednávkový systém má výpadky. Ak HTTP akcia zlyhá, flow nepadá, ale pokračuje vrstvou 3 a do logu zapíše, že systém nebol dostupný. Report potom ukáže, koľko faktúr to postihlo.
- Migrácia medzi tenantmi nie je export/import. Flow vznikol v našom tenante a sťahoval sa do tenantu klienta. Export ako balíček zoberie logiku, ale nie pripojenia: každý SharePoint URL, schránku a endpoint funkcie treba prenastaviť a všetky konektory znova overiť. Použite environment variables od začiatku, ušetrí to hodiny.
Čo by sme dnes spravili inak
Vrstvu 1 by sme od začiatku presunuli tiež do Azure Function. Porovnanie vzorov cez indexOf/substring funguje, ale pri každom novom formáte čísla objednávky rastie strom podmienok vo flowe. Jedno volanie funkcie s regexom je čitateľnejšie, testovateľné a lacné – stojí zlomok centu, zatiaľ čo správa vetveného flowu stojí čas.
Časté otázky
Vie Power Automate pracovať s regulárnymi výrazmi?
Natívne nie. V expressions sú len indexOf, substring, contains, split a podobné funkcie. Pre skutočný regex treba Azure Function, Office Script alebo konektor tretej strany. Pri pevnom formáte čísel stačia expressions, pri viacerých vzoroch sa oplatí funkcia.
Ako sa v Power Automate robí OCR faktúr?
Cez Azure Document Intelligence – buď priamo konektorom, alebo cez Azure Function. V BK používame funkciu, ktorá najprv skúsi textovú vrstvu PDF knižnicou pdfplumber a OCR volá len pre strany bez textu. Šetrí to väčšinu nákladov na OCR.
Prečo nepoužiť AI klasifikáciu na všetko?
Pre náklady, determinizmus a správu bez IT. Pravidlá a vzory sú lacné, vysvetliteľné a upraví ich účtovný tím. AI má zmysel ako ďalšia vrstva pre zvyšok, ktorý nič iné nezachytí.
Koľko stojí prevádzka takéhoto flowu?
Nízke jednotky eur mesačne za Azure Function a Document Intelligence pri objeme ~3 000 faktúr; Power Automate je súčasťou licencií Microsoft 365, ktoré firma už má. Presná suma závisí od podielu skenovaných dokumentov.
Ako sa rieši e-mail s viacerými faktúrami v jednom PDF?
Azure Function vráti pole výsledkov, jeden na faktúru. Flow pre každú položku zopakuje dotaz do objednávkového systému. Ak patria rôznym účtovníkom, e-mail sa prepošle každému z nich s poznámkou, ktorá faktúra je jeho.
Čo sa stane, keď flow zlyhá?
Chybu zachytí Scope s nastavením Run after: has failed. Zapíše sa do logu so stavom chyba a odkazom na beh, e-mail sa označí na ručné spracovanie. Žiadna faktúra sa nestratí bez záznamu.
Záver: lacné vrstvy prvé, drahé posledné
Najdôležitejšie rozhodnutie v tomto riešení nebolo technologické, ale poradie: lacné a deterministické vrstvy prvé, drahé a pravdepodobnostné posledné, a medzi nimi vrstva, ktorú si biznis spravuje sám. Rovnaký vzor funguje na objednávky, dodacie listy, reklamácie – na čokoľvek, čo prichádza do zdieľanej schránky a niekto to musí rozhodnúť.
V ďalšom diele série ukážeme, ako sme účtovný tím presvedčili, aby si pravidlá písal sám – a prečo automatizácia, ktorú si ľudia nevedia upraviť, časom umrie.
Ak riešite podobnú úlohu a chcete si návrh overiť skôr, než začnete stavať, Discovery sprint je na to: za dva týždne máte audit dát, návrh architektúry a ukážku nad vašimi reálnymi e-mailami.
Séria „Z účtárne do automatu“: 1. diel – 90 hodín mesačne · 2. diel – tento článok · Prípadová štúdia: BK a.s.