Preskoči na vsebino

spletv razvoju

Atlas za psihoterapevte

Atlas za psihoterapevte je večplatformna rešitev za psihoterapevtske prakse: zvočni posnetek seje spremeni v prepis in nato v strukturiran osnutek zapisa, terapevt pa ga pregleda, dopolni in podpiše.

atlas za psihoterapevte

Vsak, ki dela s klienti, pozna trenutek po zadnji seji dneva. Pogovori so končani, zapisi pa še čakajo, in vsaka ura zamika zabriše podrobnosti, ki so bile zjutraj še jasne. Dokumentacija je strokovna in zakonska obveznost, hkrati pa breme, ki terapevtu jemlje čas in zbranost za delo s človekom. ATLAS izhaja iz tega trenutka, zato ima eno glavno merilo: koliko časa mine od konca seje do podpisanega zapisa. Ob tem deluje na področju z najobčutljivejšimi podatki, kar jih človek lahko zaupa drugemu. Prav ta dvojna zahteva, razbremeniti terapevta, ne da bi mu vzeli presojo ali klientu zasebnost, je oblikovala vsako tehnično odločitev, opisano v nadaljevanju.

Osrednji tok je preprost za uporabo in zahteven za izvedbo. Terapevt na telefonu posname sejo ali pa po njej nareče kratek zapisek. Posnetek seje je mogoč le, če ima klient v kartoteki veljavno soglasje za snemanje. Brez njega je gumb onemogočen, strežnik pa posnetek zavrne tudi, če bi ga kdo poskusil poslati mimo vmesnika. Zvok nato obdela ozadje: pripravi prepis s časovnimi žigi in ločenima govorcema, ključne teme, predloge opravil in osnutek po razdelkih izbrane predloge, na primer SOAP ali DAP. Vsaka točka osnutka nosi sklic na odsek prepisa, zato jo terapevt preveri v nekaj sekundah, ne da bi znova poslušal celo uro. Predlogi pridejo v zapis šele, ko jih terapevt sprejme, podpiše pa ga vedno človek. Umetna inteligenca pomaga pri dokumentiranju, strokovne presoje pa ne nadomešča.

Tehnično ATLAS sestavljajo štirje repozitoriji. Zaledje v Pythonu 3.13 s FastAPI in Pydantic v2 je edini vir resnice. Spletna aplikacija je napisana v Nuxt 4, Vue 3 in TypeScriptu, Android aplikacija v Kotlinu in Jetpack Compose, četrti repozitorij pa je wiki v Nuxt Content, ki se posodobi v isti spremembi kot koda. Vsi odjemalci govorijo z istim API-jem s 244 končnimi točkami pod /api/v1, ki ga določa zapisana HTTP pogodba. Pogodba ni le dokument: zaledje samo ustvari primere odgovorov, ki jih berejo Android testi, zato se neskladje med strežnikom in telefonom pokaže kot rdeč test v CI, ne kot napaka pri uporabniku.

Zaledje uporablja MongoDB kot replica set, ker morajo nekateri zapisi v več zbirk uspeti skupaj ali pa sploh ne, to pa omogočajo le transakcije. Koda je razdeljena v plasti route, service in repository. Poti so tanke, poslovna logika živi v storitvah, do zbirk pa dostopajo le repozitoriji. Ta razdelitev ni estetska. Vsak repozitorij s podatki prakse vsaki poizvedbi sam doda identifikator organizacije, praksa pa se vedno izpelje iz prijavljene seje, nikoli iz parametra v zahtevku. Razvijalec filtra zato ne more pozabiti. Tuj ali neobstoječ ID vrne 404, ne da bi razkril, ali zapis sploh obstaja, poskus pa se zabeleži v revizijski dnevnik.

Dolga opravila ne smejo zadrževati zahtevkov, zato ob API-ju teče ločen worker. Oba procesa delita isto kodo domene, repozitorijev in storitev, worker pa nima HTTP vmesnika. Posle jemlje iz vrste v MongoDB in skrbi za prepise, AI-obdelavo, izvoze kartotek in redna čiščenja, od začasnih datotek do kopij pri zunanjih ponudnikih. Napaka, ki je ponovni poskus ne more popraviti, posel takoj označi kot neuspešen, druge se ponovijo, terapevt pa lahko neuspelo obdelavo sproži znova brez ponovnega nalaganja.

Ker platforma obdeluje posebej občutljive podatke, varnost ni dodatek, temveč del arhitekture. Klinična besedila, kot so zapisi, prepisi, uvozi in odgovori na vprašalnike, so šifrirana z AES-256-GCM že na ravni aplikacije, zato bi tudi ukradena kopija baze pokazala le šifrirano vsebino. Zvok, dokumenti in izvozi so v S3 hrambi s šifriranjem na strežniku, prenašajo pa se le prek podpisanih povezav, ki veljajo nekaj minut. Posnetek se privzeto izbriše sedem dni po podpisu zapisa, praksa pa lahko izbere takojšnji izbris ali 30 dni. Prijava za vse zahteva dvostopenjsko preverjanje s TOTP, števci poskusov tečejo ločeno na sejo, uporabnika in dan, ob zaklepu pa uporabnik dobi opozorilo po e-pošti. Vloge so ostro ločene: platformski skrbnik do kliničnih podatkov praks nima dostopa, lastnik prakse ga nima samodejno, revizijski dnevnik pa beleži, kdo je kdaj kaj odprl, uredil, podpisal ali izvozil, nikoli pa same vsebine. Dnevniki, e-pošta in obvestila ne vsebujejo imen klientov, naložene dokumente pa pregleda ClamAV.

Pri umetni inteligenci je ključna zamenljivost. Ponudnika prepisa in jezikovnega modela sta skrita za enotnim vmesnikom in se izbereta s spremenljivko okolja, zato menjava ne zahteva spremembe kode. V razvoju in testih teče sintetični ponudnik z izmišljenimi podatki, lokalno pa faster-whisper na grafični kartici. Za produkcijo sta pripravljena Soniox in Speechmatics z obdelavo v EU. ATLAS kopijo pri ponudniku izbriše takoj po prepisu, redno čiščenje pa ujame tudi tiste, ki bi ostale. Osnutke pripravlja Claude prek Vertex AI v regiji EU z uradnim SDK. Povezava je implementirana in testirana, dejanska uporaba pa še čaka na odobritev kvote. Vsak AI posel hrani namen, ponudnika, model, različico in vire, iz katerih je nastal.

Najpomembnejši del umetne inteligence je tisti, ki ga uporabnik ne vidi. Model dobi natančna navodila, njegov izhod pa nato preveri še strežnik z varovali. Ta zavrnejo vsako diagnozo, diagnostično oznako, oceno tveganja ali priporočilo zdravljenja. Meja je postavljena natančno. Stavek »Klient je omenil samomorilne misli.« sme v osnutek, ker poroča, kaj je bilo rečeno. Stavek »Visoko tveganje za samomor.« ne sme, ker je klinična ocena, ta pa pripada terapevtu. Varovala so preverjena na korpusu 179 primerov, med katerimi so tako stavki, ki morajo skozi, kot tisti, ki ne smejo.

Android aplikacija je zgrajena okoli zanesljivega snemanja, saj izgubljen posnetek pomeni izgubljeno sejo. Snemanje teče v storitvi v ospredju, zato deluje tudi pri ugasnjenem zaslonu do tri ure, ob telefonskem klicu pa se samodejno ustavi in ponudi nadaljevanje. Zvok se že med snemanjem šifrira s Tink (AES-256-GCM-HKDF, ključ v Android Keystore). Če proces nenadoma umre, aplikacija datoteko reši do zadnjega celega segmenta, kar pomeni izgubo največ nekaj kilobajtov. WorkManager posnetek nalaga po kosih po 8 MiB, vsak kos ima kontrolno vsoto SHA-256, prenos pa se po prekinitvi nadaljuje pri prvem manjkajočem kosu. Z naprave se posnetek izbriše šele, ko strežnik potrdi prejem. Klinični zasloni imajo onemogočene posnetke zaslona, aplikacija se po petih minutah neaktivnosti zaklene z biometrijo ali PIN-om, en račun pa lahko poveže največ dva telefona. Arhitektura je MVVM s StateFlow, omrežni sloj pa Retrofit in OkHttp s kotlinx.serialization.

Spletna aplikacija v Nuxt 4 loči dva svetova. Javne strani se izrišejo na strežniku zaradi hitrosti, iskalnikov in pravilnih jezikovnih različic. Delovni del aplikacije teče kot SPA brez strežniškega izrisa in je zaprt za iskalnike, tako da strežnik kliničnih podatkov nikoli ne izrisuje. Celoten sistem je dvojezičen: slovenščina in angleščina veljata za vmesnik, sporočila API-ja, e-pošto, PDF-je in Android aplikacijo. Dostopnost po WCAG 2.2 AA preverja axe v Playwright testih. Center za pomoč v aplikaciji in PDF navodila nastaneta iz istega vira, zato si ne moreta nasprotovati.

Integracije so izbrane tam, kjer prihranijo korak. Stripe skrbi za naročnine prek Checkout in Billing. Podpisani webhooki se shranijo enkrat in obdelajo v workerju, zato podvojen dogodek ne more dvakrat spremeniti naročnine. Zoom se poveže prek OAuth za vsakega terapevta posebej: ATLAS ustvari sestanek z nevtralnim naslovom, po koncu pa samodejno prevzame povzetek Zoom AI Companion kot vir seje, nikoli neposredno v podpisan zapis. Push obvestila prek FCM in e-pošta ne vsebujejo imen klientov, povezava do koledarja ICS pa se ob varnostnih dogodkih samodejno prekliče. Za supervizijo ATLAS pripravi psevdonimizirane primere, strežniška pravila pa pred deljenjem poiščejo osebne podatke tudi v sklonih in imenih priponk.

Zanesljivost razvoja podpira več kot 3.500 avtomatiziranih testov: skoraj 2.000 v pytestu za zaledje, okoli 1.000 v Vitestu za splet, 565 za Android in 42 celovitih tokov v Playwrightu, ki ključne poti preverijo skozi pravi brskalnik. GitHub Actions jih poganja v vseh štirih repozitorijih. Vsaka sprememba pogodbe se v isti seji prenese v zaledje, oba odjemalca in wiki. Za objavo sta pripravljena Docker Compose in Caddy.

Projekt še ni javno objavljen in je v zaključnem preizkušanju. Pravi preizkus ne bo število testov ali končnih točk, temveč merilo z začetka: ali terapevt zvečer zapre računalnik prej kot včeraj, ne da bi pri tem zaupal manj. Pri gradnji se je najtežje vprašanje izkazalo za netehnično. Ni šlo za to, kaj umetna inteligenca zmore, ampak za to, ali bi ji terapevt zaupal zgodbo svojega klienta. Vsaka odločitev v tem besedilu je poskus odgovora na to vprašanje.