cry-vetzdravila 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +17 -0
- package/CLAUDE.md +82 -0
- package/LICENSE.md +16 -0
- package/README.md +376 -0
- package/a.txt +1643 -0
- package/bun.lock +197 -0
- package/dist/atcvet/opisATCvetKode.d.ts +23 -0
- package/dist/atcvet/podatkiATCvetKode.d.ts +20 -0
- package/dist/atcvet/pomeniNivojevATCvet.d.ts +1 -0
- package/dist/atcvet/types/AtcvetFile.d.ts +19 -0
- package/dist/generated/AtcVet.d.ts +9 -0
- package/dist/generated/RegisterZdravil.d.ts +8 -0
- package/dist/generated/seznamZdravil.d.ts +8 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +141786 -0
- package/dist/register/MIN_OCENA_PODOBNOSTI.d.ts +2 -0
- package/dist/register/helper/normalizirajNaziv.d.ts +176 -0
- package/dist/register/helper/oblikujRezultatIskanja.d.ts +8 -0
- package/dist/register/helper/oceniPodobnost.d.ts +37 -0
- package/dist/register/helper/poisciZivalskoVrsto.d.ts +33 -0
- package/dist/register/helper/razcleniNaziv.d.ts +2 -0
- package/dist/register/podobnaZdravilaPoATC.d.ts +16 -0
- package/dist/register/podobnaZdravilaPoUcinkovinah.d.ts +18 -0
- package/dist/register/registerZdravil.d.ts +9 -0
- package/dist/register/types/KarencaZdravila.d.ts +24 -0
- package/dist/register/types/PotUporabeZdravila.d.ts +21 -0
- package/dist/register/types/RazclembaZdravila.d.ts +9 -0
- package/dist/register/types/RegisterZdravil.d.ts +2 -0
- package/dist/register/types/UcinkovinaZdravila.d.ts +20 -0
- package/dist/register/types/Zdravilo.d.ts +65 -0
- package/dist/register/types/ZdraviloZUtemeljitvijo.d.ts +9 -0
- package/dist/register/types/ZivalskeVrste.d.ts +158 -0
- package/dist/register/uganiZdravilo.d.ts +43 -0
- package/dist/register/zdravilaZaAtcVetKodo.d.ts +8 -0
- package/dist/register/zdraviloJeVakcinaZa.d.ts +18 -0
- package/docs/vakcine.md +195 -0
- package/package.json +39 -0
- package/src/atcvet/CLAUDE.md +18 -0
- package/src/atcvet/downloadLatestAtcvetPdf.ts +107 -0
- package/src/atcvet/opisATCvetKode.ts +116 -0
- package/src/atcvet/parseAtcvetPdf.ts +215 -0
- package/src/atcvet/podatkiATCvetKode.ts +34 -0
- package/src/atcvet/pomeniNivojevATCvet.ts +8 -0
- package/src/atcvet/types/AtcvetFile.ts +22 -0
- package/src/generate.ts +111 -0
- package/src/generated/AtcVet.ts +56704 -0
- package/src/generated/seznamZdravil.ts +44833 -0
- package/src/importParseAndBuildAll.ts +97 -0
- package/src/index.ts +289 -0
- package/src/interactive.ts +428 -0
- package/src/register/CLAUDE.md +230 -0
- package/src/register/MIN_OCENA_PODOBNOSTI.ts +3 -0
- package/src/register/downloadRegister.ts +148 -0
- package/src/register/helper/analizaVakcin.ts +90 -0
- package/src/register/helper/checkVrste.ts +72 -0
- package/src/register/helper/hashString.ts +27 -0
- package/src/register/helper/normalizirajNaziv.ts +493 -0
- package/src/register/helper/oblikujRezultatIskanja.ts +15 -0
- package/src/register/helper/oceniPodobnost.ts +194 -0
- package/src/register/helper/poisciZivalskoVrsto.ts +100 -0
- package/src/register/helper/razcleniNaziv.ts +105 -0
- package/src/register/helper/testNormalizacije.ts +89 -0
- package/src/register/helper/testPodobnosti.ts +238 -0
- package/src/register/helper/testVakcin.ts +103 -0
- package/src/register/parseRegister.ts +464 -0
- package/src/register/podobnaZdravilaPoATC.ts +71 -0
- package/src/register/podobnaZdravilaPoUcinkovinah.ts +136 -0
- package/src/register/registerZdravil.ts +22 -0
- package/src/register/stats.ts +114 -0
- package/src/register/types/KarencaZdravila.ts +26 -0
- package/src/register/types/PotUporabeZdravila.ts +21 -0
- package/src/register/types/RazclembaZdravila.ts +10 -0
- package/src/register/types/RegisterRaw.ts +23 -0
- package/src/register/types/RegisterZdravil.ts +3 -0
- package/src/register/types/UcinkovinaZdravila.ts +21 -0
- package/src/register/types/Zdravilo.ts +84 -0
- package/src/register/types/ZdraviloZUtemeljitvijo.ts +11 -0
- package/src/register/types/ZivalskeVrste.ts +7 -0
- package/src/register/uganiZdravilo.ts +142 -0
- package/src/register/zdravilaZaAtcVetKodo.ts +28 -0
- package/src/register/zdraviloJeVakcinaZa.ts +202 -0
- package/src/test/testPodobnosti.test.ts +126 -0
- package/src/test/zdravila.json +38693 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaktivno iskanje zdravil
|
|
3
|
+
*
|
|
4
|
+
* Uporabnik vnese ime zdravila in dobi rezultate.
|
|
5
|
+
* Ukazi:
|
|
6
|
+
* 1-20: nastavi limit rezultatov
|
|
7
|
+
* u: vklopi/izklopi utemeljitve
|
|
8
|
+
* r: vklopi/izklopi razčlembe
|
|
9
|
+
* q: izhod
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as readline from "readline";
|
|
13
|
+
import { uganiZdraviloInUtemelji } from "./register/uganiZdravilo";
|
|
14
|
+
import { razcleniNaziv } from "./register/helper/razcleniNaziv";
|
|
15
|
+
import { oblikujRezultatIskanja } from "./register/helper/oblikujRezultatIskanja";
|
|
16
|
+
import { oceniPodobnost } from "./register/helper/oceniPodobnost";
|
|
17
|
+
import { MIN_OCENA_PODOBNOSTI } from "./register/MIN_OCENA_PODOBNOSTI";
|
|
18
|
+
import { opisATCvetKode, izracunajNivoje } from "./atcvet/opisATCvetKode";
|
|
19
|
+
import { podatkiATCvetKode } from "./atcvet/podatkiATCvetKode";
|
|
20
|
+
import { podobnaZdravilaPoATC } from "./register/podobnaZdravilaPoATC";
|
|
21
|
+
import { podobnaZdravilaPoUcinkovinah } from "./register/podobnaZdravilaPoUcinkovinah";
|
|
22
|
+
import { zdravilaZaAtcVetKodo } from "./register/zdravilaZaAtcVetKodo";
|
|
23
|
+
|
|
24
|
+
// ANSI color codes
|
|
25
|
+
const GREEN = "\x1b[32m";
|
|
26
|
+
const YELLOW = "\x1b[33m";
|
|
27
|
+
const BLUE = "\x1b[34m";
|
|
28
|
+
const GRAY = "\x1b[90m";
|
|
29
|
+
const RESET = "\x1b[0m";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Vrne string z ocenami, ki niso 0
|
|
33
|
+
*/
|
|
34
|
+
function formatirajOcene(u: { ocenaPrvihBesed: number; ocenaVelikosti: number; ocenaDoze: number; ocenaZivalskihVrst: number; ocenaTeze: number; ocenaKolicine: number; ocenaBesed: number; steviloBesed: number }): string {
|
|
35
|
+
const deli: string[] = [];
|
|
36
|
+
if (u.ocenaPrvihBesed !== 0) deli.push(`${GRAY}besede:${RESET}${u.ocenaPrvihBesed}`);
|
|
37
|
+
if (u.ocenaVelikosti !== 0) deli.push(`${GRAY}velikost:${RESET}${u.ocenaVelikosti}`);
|
|
38
|
+
if (u.ocenaDoze !== 0) deli.push(`${GRAY}doze:${RESET}${u.ocenaDoze}`);
|
|
39
|
+
if (u.ocenaZivalskihVrst !== 0) deli.push(`${GRAY}vrste:${RESET}${u.ocenaZivalskihVrst}`);
|
|
40
|
+
if (u.ocenaTeze !== 0) deli.push(`${GRAY}teza:${RESET}${u.ocenaTeze}`);
|
|
41
|
+
if (u.ocenaKolicine !== 0) deli.push(`${GRAY}kolicina:${RESET}${u.ocenaKolicine}`);
|
|
42
|
+
if (u.ocenaBesed !== 0) deli.push(`${GRAY}besede2:${RESET}${u.ocenaBesed}`);
|
|
43
|
+
if (u.steviloBesed !== 0) deli.push(`${GRAY}stBesed:${RESET}${u.steviloBesed}`);
|
|
44
|
+
return deli.join(" ");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let limit = 5;
|
|
48
|
+
let minOcena = MIN_OCENA_PODOBNOSTI;
|
|
49
|
+
let utemelji = false;
|
|
50
|
+
let razclembe = false;
|
|
51
|
+
let zadnjeIskanje: string | null = null;
|
|
52
|
+
let zadnjiRezultati: ReturnType<typeof uganiZdraviloInUtemelji> = [];
|
|
53
|
+
let atcNivo = 5;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Parsira kombinirane ukaze (npr. "ur3", "r5u", "10ur", "500u")
|
|
57
|
+
* Vrne true če je bil ukaz procesiran, false če je iskanje
|
|
58
|
+
*/
|
|
59
|
+
function parseCommand(input: string): boolean {
|
|
60
|
+
// Vzorec za kombinirane ukaze: poljubna kombinacija u, r in števila
|
|
61
|
+
const commandPattern = /^([ur]|\d+)+$/i;
|
|
62
|
+
if (!commandPattern.test(input)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let hasCommand = false;
|
|
67
|
+
let newLimit: number | null = null;
|
|
68
|
+
let newMinOcena: number | null = null;
|
|
69
|
+
let toggleU = false;
|
|
70
|
+
let toggleR = false;
|
|
71
|
+
|
|
72
|
+
// Poišči vsa števila
|
|
73
|
+
const numMatches = input.match(/\d+/g);
|
|
74
|
+
if (numMatches) {
|
|
75
|
+
for (const match of numMatches) {
|
|
76
|
+
const num = parseInt(match, 10);
|
|
77
|
+
// 1-20 = limit
|
|
78
|
+
if (num >= 1 && num <= 20) {
|
|
79
|
+
newLimit = num;
|
|
80
|
+
hasCommand = true;
|
|
81
|
+
}
|
|
82
|
+
// 200-2000 = minOcena
|
|
83
|
+
else if (num >= 200 && num <= 2000) {
|
|
84
|
+
newMinOcena = num;
|
|
85
|
+
hasCommand = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Preštej u in r
|
|
91
|
+
for (const char of input.toLowerCase()) {
|
|
92
|
+
if (char === "u") {
|
|
93
|
+
toggleU = !toggleU;
|
|
94
|
+
hasCommand = true;
|
|
95
|
+
} else if (char === "r") {
|
|
96
|
+
toggleR = !toggleR;
|
|
97
|
+
hasCommand = true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!hasCommand) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Uporabi ukaze
|
|
106
|
+
if (newLimit !== null) {
|
|
107
|
+
limit = newLimit;
|
|
108
|
+
}
|
|
109
|
+
if (newMinOcena !== null) {
|
|
110
|
+
minOcena = newMinOcena;
|
|
111
|
+
}
|
|
112
|
+
if (toggleU) {
|
|
113
|
+
utemelji = !utemelji;
|
|
114
|
+
}
|
|
115
|
+
if (toggleR) {
|
|
116
|
+
razclembe = !razclembe;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function printResult(vhod: string) {
|
|
123
|
+
zadnjeIskanje = vhod;
|
|
124
|
+
const rezultati = uganiZdraviloInUtemelji(vhod, { limit, minOcena });
|
|
125
|
+
zadnjiRezultati = rezultati;
|
|
126
|
+
const { zadetki, najboljsi } = oblikujRezultatIskanja(rezultati);
|
|
127
|
+
|
|
128
|
+
if (zadetki.length === 0) {
|
|
129
|
+
console.log(" Ni zadetkov.\n");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Izpiši razčlembo in utemeljitev vhoda
|
|
134
|
+
const razclembaVhoda = razcleniNaziv(vhod);
|
|
135
|
+
if (utemelji) {
|
|
136
|
+
const uVhoda = oceniPodobnost(razclembaVhoda, razclembaVhoda);
|
|
137
|
+
console.log(` Vhod: ${formatirajOcene(uVhoda)}`);
|
|
138
|
+
}
|
|
139
|
+
if (razclembe) {
|
|
140
|
+
console.log(` Vhod: ${GRAY}besede=[${RESET}${razclembaVhoda.besede.join(", ")}${GRAY}] doze=[${RESET}${razclembaVhoda.doze.join(", ")}${GRAY}] teza=${RESET}${razclembaVhoda.teza || "-"}${GRAY} vrste=[${RESET}${razclembaVhoda.zivalskeVrste.join(", ")}${GRAY}]${RESET}`);
|
|
141
|
+
}
|
|
142
|
+
if (utemelji || razclembe) {
|
|
143
|
+
console.log();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < rezultati.length; i++) {
|
|
147
|
+
const r = rezultati[i];
|
|
148
|
+
const u = r.utemeljitev;
|
|
149
|
+
const jeNajboljsi = najboljsi && r.zdravilo.ime === najboljsi.ime;
|
|
150
|
+
|
|
151
|
+
// Zelena barva za najboljšega
|
|
152
|
+
const colorStart = jeNajboljsi ? GREEN : "";
|
|
153
|
+
const colorEnd = jeNajboljsi ? RESET : "";
|
|
154
|
+
|
|
155
|
+
console.log(`${colorStart} ${i + 1}. ${GRAY}[${RESET}${YELLOW}${u.ocena}${RESET}${GRAY}]${RESET}${colorStart} ${r.zdravilo.ime}${colorEnd} ${BLUE}${r.zdravilo.atcKoda}${RESET}`);
|
|
156
|
+
|
|
157
|
+
if (utemelji) {
|
|
158
|
+
console.log(` ${formatirajOcene(u)}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (razclembe) {
|
|
162
|
+
const rr = u.razclembaRegistra;
|
|
163
|
+
console.log(` ${GRAY}besede=[${RESET}${rr.besede.join(", ")}${GRAY}] doze=[${RESET}${rr.doze.join(", ")}${GRAY}] teza=${RESET}${rr.teza || "-"}${GRAY} vrste=[${RESET}${rr.zivalskeVrste.join(", ")}${GRAY}]${RESET}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.log();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function printHelp() {
|
|
171
|
+
console.log("───────────────────────────────────────────────────────────────");
|
|
172
|
+
console.log(" Ukazi (lahko kombinirani, npr. ur3, 10u, r5):");
|
|
173
|
+
console.log(" 1-20 Nastavi limit rezultatov");
|
|
174
|
+
console.log(" 200-2000 Nastavi minimalno oceno");
|
|
175
|
+
console.log(" u Vklopi/izklopi utemeljitve (ocene)");
|
|
176
|
+
console.log(" r Vklopi/izklopi razčlembe (besede, doze, teža, vrste)");
|
|
177
|
+
console.log(" o Izpiši opis ATCvet kode prvega zadetka");
|
|
178
|
+
console.log(" p Izpiši vse podatke ATCvet kode prvega zadetka");
|
|
179
|
+
console.log(" = Izpiši podobna zdravila (po ATCvet kodi)");
|
|
180
|
+
console.log(" +/- Dvigni/spusti ATCvet nivo in izpiši podobna");
|
|
181
|
+
console.log(" f Izpiši podobna zdravila (po učinkovinah)");
|
|
182
|
+
console.log(" Qxxxx Prikaži nivoje ATCvet kode (npr. QJ01CA04)");
|
|
183
|
+
console.log(" Qxxxx... Prikaži zdravila z ATCvet kodo (npr. QJ01...)");
|
|
184
|
+
console.log(" q Izhod");
|
|
185
|
+
console.log("───────────────────────────────────────────────────────────────\n");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function printStatus() {
|
|
189
|
+
console.log(` ${GRAY}Limit:${RESET} ${limit}, ${GRAY}MinOcena:${RESET} ${minOcena}, ${GRAY}Utemeljitve:${RESET} ${utemelji ? "DA" : "NE"}, ${GRAY}Razčlembe:${RESET} ${razclembe ? "DA" : "NE"}\n`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function printOpisATCvet() {
|
|
193
|
+
if (zadnjiRezultati.length === 0) {
|
|
194
|
+
console.log(" Ni zadetkov.\n");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const zdravilo = zadnjiRezultati[0].zdravilo;
|
|
198
|
+
const opis = opisATCvetKode(zdravilo.atcKoda);
|
|
199
|
+
if (opis) {
|
|
200
|
+
console.log(` ${BLUE}${zdravilo.atcKoda}${RESET} ${GRAY}(${opis.pomenNivoja})${RESET} ${opis.opisNivoja}\n`);
|
|
201
|
+
} else {
|
|
202
|
+
console.log(` ${BLUE}${zdravilo.atcKoda}${RESET} - ni opisa\n`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function printPodatkiATCvet() {
|
|
207
|
+
if (zadnjiRezultati.length === 0) {
|
|
208
|
+
console.log(" Ni zadetkov.\n");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const zdravilo = zadnjiRezultati[0].zdravilo;
|
|
212
|
+
const podatki = podatkiATCvetKode(zdravilo.atcKoda);
|
|
213
|
+
if (podatki.length === 0) {
|
|
214
|
+
console.log(` ${BLUE}${zdravilo.atcKoda}${RESET} - ni podatkov\n`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
console.log(` ${BLUE}${zdravilo.atcKoda}${RESET}`);
|
|
218
|
+
for (const p of podatki) {
|
|
219
|
+
console.log(` ${GRAY}${p.pomenNivoja}:${RESET} ${p.opisNivoja}`);
|
|
220
|
+
}
|
|
221
|
+
console.log();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function printPodobnaZdravila() {
|
|
225
|
+
if (zadnjiRezultati.length === 0) {
|
|
226
|
+
console.log(" Ni zadetkov.\n");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const zdravilo = zadnjiRezultati[0].zdravilo;
|
|
230
|
+
const podobna = podobnaZdravilaPoATC(zdravilo, atcNivo);
|
|
231
|
+
|
|
232
|
+
// Pridobi opis nivoja
|
|
233
|
+
const nivoOpisi: Record<number, string> = {
|
|
234
|
+
1: "anatomska glavna skupina",
|
|
235
|
+
2: "terapevtska podskupina",
|
|
236
|
+
3: "farmakološka podskupina",
|
|
237
|
+
4: "kemijska podskupina",
|
|
238
|
+
5: "kemijska učinkovina",
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// Pridobi konkreten opis za ta nivo iz ATCvet kode
|
|
242
|
+
const nivoji = izracunajNivoje(zdravilo.atcKoda);
|
|
243
|
+
const nivoKoda = nivoji[atcNivo]; // nivoji[0]=Q, nivoji[1]=QA, ... nivoji[5]=polna koda
|
|
244
|
+
const opisNivoja = nivoKoda ? opisATCvetKode(nivoKoda)?.opisNivoja : null;
|
|
245
|
+
|
|
246
|
+
const opisDel = opisNivoja ? `: ${opisNivoja}` : "";
|
|
247
|
+
console.log(` ${GRAY}Nivo ${atcNivo} (${nivoOpisi[atcNivo]}${opisDel}):${RESET} ${podobna.length} podobnih`);
|
|
248
|
+
if (podobna.length === 0) {
|
|
249
|
+
console.log();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
for (const z of podobna) {
|
|
253
|
+
console.log(` ${z.ime} ${BLUE}${z.atcKoda}${RESET}`);
|
|
254
|
+
}
|
|
255
|
+
console.log();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function printPodobnaZdravilaPoUcinkovinah() {
|
|
259
|
+
if (zadnjiRezultati.length === 0) {
|
|
260
|
+
console.log(" Ni zadetkov.\n");
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const zdravilo = zadnjiRezultati[0].zdravilo;
|
|
264
|
+
const podobna = podobnaZdravilaPoUcinkovinah(zdravilo);
|
|
265
|
+
|
|
266
|
+
// Pridobi učinkovine iz zdravila
|
|
267
|
+
const ucinkovine = zdravilo.ucinkovine.map(u => u.ucinkovina).join(", ");
|
|
268
|
+
|
|
269
|
+
console.log(` ${GRAY}Podobna po učinkovinah (${ucinkovine || "ni učinkovin"}):${RESET} ${podobna.length} podobnih`);
|
|
270
|
+
if (podobna.length === 0) {
|
|
271
|
+
console.log();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
for (const z of podobna) {
|
|
275
|
+
console.log(` ${z.ime} ${BLUE}${z.atcKoda}${RESET}`);
|
|
276
|
+
}
|
|
277
|
+
console.log();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Prikaže nivoje ATCvet kode
|
|
282
|
+
*/
|
|
283
|
+
function printATCvetNivoji(atcKoda: string) {
|
|
284
|
+
const podatki = podatkiATCvetKode(atcKoda);
|
|
285
|
+
if (podatki.length === 0) {
|
|
286
|
+
console.log(` ${BLUE}${atcKoda}${RESET} - ni podatkov\n`);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
console.log(` ${BLUE}${atcKoda}${RESET}`);
|
|
290
|
+
for (const p of podatki) {
|
|
291
|
+
console.log(` ${GRAY}${p.pomenNivoja}:${RESET} ${p.opisNivoja}`);
|
|
292
|
+
}
|
|
293
|
+
console.log();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Prikaže seznam zdravil z dano ATCvet kodo (ali prefiksom)
|
|
298
|
+
*/
|
|
299
|
+
function printZdravilaZATCvetKodo(atcKoda: string) {
|
|
300
|
+
const koda = atcKoda.toUpperCase();
|
|
301
|
+
const zdravila = zdravilaZaAtcVetKodo(koda);
|
|
302
|
+
|
|
303
|
+
console.log(` ${GRAY}Zdravila z ATCvet kodo ${BLUE}${koda}${RESET}${GRAY}:${RESET} ${zdravila.length}`);
|
|
304
|
+
if (zdravila.length === 0) {
|
|
305
|
+
console.log();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
for (const z of zdravila) {
|
|
309
|
+
console.log(` ${z.ime} ${BLUE}${z.atcKoda}${RESET}`);
|
|
310
|
+
}
|
|
311
|
+
console.log();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function main() {
|
|
315
|
+
const rl = readline.createInterface({
|
|
316
|
+
input: process.stdin,
|
|
317
|
+
output: process.stdout,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
console.log("\n═══════════════════════════════════════════════════════════════");
|
|
321
|
+
console.log(" INTERAKTIVNO ISKANJE ZDRAVIL");
|
|
322
|
+
console.log("═══════════════════════════════════════════════════════════════\n");
|
|
323
|
+
printHelp();
|
|
324
|
+
printStatus();
|
|
325
|
+
|
|
326
|
+
const prompt = () => {
|
|
327
|
+
rl.question("Vnesi ime zdravila: ", (input) => {
|
|
328
|
+
const trimmed = input.trim();
|
|
329
|
+
|
|
330
|
+
if (trimmed === "q" || trimmed === "quit" || trimmed === "exit") {
|
|
331
|
+
console.log("\nNasvidenje!\n");
|
|
332
|
+
rl.close();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Prazen vnos = ponovi zadnje iskanje
|
|
337
|
+
if (trimmed === "") {
|
|
338
|
+
if (zadnjeIskanje) {
|
|
339
|
+
console.log();
|
|
340
|
+
printResult(zadnjeIskanje);
|
|
341
|
+
}
|
|
342
|
+
prompt();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Check for help
|
|
347
|
+
if (trimmed === "?" || trimmed === "help") {
|
|
348
|
+
printHelp();
|
|
349
|
+
prompt();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Check for ATCvet commands
|
|
354
|
+
if (trimmed === "o") {
|
|
355
|
+
printOpisATCvet();
|
|
356
|
+
prompt();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (trimmed === "p") {
|
|
360
|
+
printPodatkiATCvet();
|
|
361
|
+
prompt();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (trimmed === "=") {
|
|
365
|
+
printPodobnaZdravila();
|
|
366
|
+
prompt();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (trimmed === "+") {
|
|
370
|
+
if (atcNivo < 5) {
|
|
371
|
+
atcNivo++;
|
|
372
|
+
}
|
|
373
|
+
printPodobnaZdravila();
|
|
374
|
+
prompt();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (trimmed === "-") {
|
|
378
|
+
if (atcNivo > 1) {
|
|
379
|
+
atcNivo--;
|
|
380
|
+
}
|
|
381
|
+
printPodobnaZdravila();
|
|
382
|
+
prompt();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (trimmed === "f") {
|
|
386
|
+
printPodobnaZdravilaPoUcinkovinah();
|
|
387
|
+
prompt();
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Check for ATCvet code input (starts with Q)
|
|
392
|
+
if (trimmed.toUpperCase().startsWith("Q")) {
|
|
393
|
+
// Check if ends with ... -> show medicines list
|
|
394
|
+
if (trimmed.endsWith("...")) {
|
|
395
|
+
const atcKoda = trimmed.slice(0, -3).trim();
|
|
396
|
+
printZdravilaZATCvetKodo(atcKoda);
|
|
397
|
+
} else {
|
|
398
|
+
// Show levels of the ATCvet code
|
|
399
|
+
printATCvetNivoji(trimmed);
|
|
400
|
+
}
|
|
401
|
+
prompt();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Check for combined commands (u, r, 1-20 in any combination)
|
|
406
|
+
if (parseCommand(trimmed)) {
|
|
407
|
+
printStatus();
|
|
408
|
+
if (zadnjeIskanje) {
|
|
409
|
+
printResult(zadnjeIskanje);
|
|
410
|
+
}
|
|
411
|
+
prompt();
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Search
|
|
416
|
+
console.log();
|
|
417
|
+
printResult(trimmed);
|
|
418
|
+
prompt();
|
|
419
|
+
});
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
prompt();
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
main().catch((e) => {
|
|
426
|
+
console.error("Napaka:", e);
|
|
427
|
+
process.exit(1);
|
|
428
|
+
});
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Namen projekta Register zdravil
|
|
2
|
+
|
|
3
|
+
1. Podatke zajamemo s spletne strani https://www.jazmp.si/veterinarska-zdravila/podatki-o-zdravilih/seznam-zdravil v datoteki xlsx (**downloadRegister**).
|
|
4
|
+
2. Datoteko sparsamo v json datoteko (**parseRegister**)
|
|
5
|
+
3. Poiščemo po nazivu najbolj ustrezna zdravila (**uganiZdravilo**)
|
|
6
|
+
1. Imena zdravil normaliziramo (**normalizirajNaziv**)
|
|
7
|
+
2. Normalizirano ime razčlenimi (**razcleniNaziv**)
|
|
8
|
+
|
|
9
|
+
## Tehnična specifikacija
|
|
10
|
+
|
|
11
|
+
### downloadRegister.ts
|
|
12
|
+
|
|
13
|
+
1. Funkcija z direktorij data prenese .xlsx datoteko s spletne strani.
|
|
14
|
+
2. Url datoteke poišče tako, da v html kodi spletne strani najde vse <a> zapise, kjer se href začne z "https://www.jazmp.si/fileadmin/datoteke/seznami/SRZV".
|
|
15
|
+
3. Med temi datotekami poišče tisto, ki ima najnovejši datum.
|
|
16
|
+
4. Primer vsebine href-a:
|
|
17
|
+
https://www.jazmp.si/fileadmin/datoteke/seznami/SRZV/20-11-2025.xlsx
|
|
18
|
+
5. register v xslx shrani v mapo data kot register.xslx
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### parseRegister.ts
|
|
22
|
+
|
|
23
|
+
1. prebere data/register.xslx
|
|
24
|
+
2. ustvari objekte s polji
|
|
25
|
+
1. imeZdravila
|
|
26
|
+
2. imetnikDovoljenja
|
|
27
|
+
3. sproscanjeZdravila
|
|
28
|
+
4. stDzp
|
|
29
|
+
5. datumVeljavnost v obliki YYYY-MM-DD
|
|
30
|
+
6. rezimIzdaje
|
|
31
|
+
7. ATC
|
|
32
|
+
8. poti uporabe: PotUporabeZdravila[],
|
|
33
|
+
9. farmacevtskaObika
|
|
34
|
+
10. enotaKolicine
|
|
35
|
+
11. ucinkovine: UcinkovinaZdravila[]
|
|
36
|
+
12. zivalskeVrste: ZivalskaVrsta[]
|
|
37
|
+
13. karence: KarencaZdravila
|
|
38
|
+
1. zberi jih iz vseh stolpcev KARENCA...
|
|
39
|
+
1. primer: xlsx "-#Govedo\60-meso in organi\37,0\dni\I.m. (20 mg/kg t.m. dvakrat)" se preslika v { govedo: { meso: 37.0, "not. organi": 37.0 } }
|
|
40
|
+
2. primer: "605-kunci\00-\null\null\Ni dovoljena uporaba pri kuncih, ki so namenjeni prehrani ljudi." se preslika v { kunci: {} }
|
|
41
|
+
3. primer: "505-kokoši nesnice\40-jajca\0,0\dni\" se preslika v { perutnina: { jajca: 0.0 } }
|
|
42
|
+
14. poišči najbolj primerno živalsko vrsto. Če je v registru opredeljena bolj podrobno, dodaj oba zapisa.
|
|
43
|
+
1. primer: "karence": [ { "vrsta": "krave v laktaciji", "karence": { "meso": 7, "mleko": 5 } } ] dobi tudi objekt { "vrsta": "govedo", "karence": { "meso": 7, "mleko": 5 } }
|
|
44
|
+
2. primer: [ { "vrsta": "krave", "karence": { "meso": 2, "mleko": 0 } }, { "vrsta": "telice", "karence": { "meso": 2, "mleko": 0 } } ] se preslika v [{ "vrsta": "govedo", "karence": { "meso": 2, "mleko": 0 } }, { "vrsta": "telice", "karence": { "meso": 2, "mleko": 0 } }] - ker so krave govedo in telice del krav
|
|
45
|
+
15. pri določitvi živalske vrste (pri poljih zivalskeVrste in karence) si pomagaj s poljem _match iz skupneEntitete.vrsteZivali
|
|
46
|
+
16. za vsako zdravilo izpolni polje vakcinaZa?: string[] s klicem zdraviloJeVakcinaZa
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### normalizirajNaziv.ts
|
|
50
|
+
Funkcija **normalizirajNaziv** v src/normalizirajNaziv
|
|
51
|
+
1. čiščenje imena - vsako od točk implementiraj v svoji funkciji
|
|
52
|
+
1. toLocaleLowercase za "si-SL"
|
|
53
|
+
2. zamenjaj vse " za " s " "
|
|
54
|
+
3. zamenjaj decimalne vejice med dvemi številkami z decimalno piko
|
|
55
|
+
4. zamenjaj posebne znake + ( ) , ; * s presledki
|
|
56
|
+
5. zamenjaj i.e. z ie
|
|
57
|
+
6. ustvari const ENOTE
|
|
58
|
+
1. enote so
|
|
59
|
+
1. g
|
|
60
|
+
2. mg
|
|
61
|
+
3. mcg
|
|
62
|
+
4. kg
|
|
63
|
+
5. l
|
|
64
|
+
6. ml
|
|
65
|
+
7. dl
|
|
66
|
+
8. deci
|
|
67
|
+
9. ie
|
|
68
|
+
10. tbl
|
|
69
|
+
11. cap
|
|
70
|
+
12. caps
|
|
71
|
+
13. kap
|
|
72
|
+
14. kps
|
|
73
|
+
15. kaps
|
|
74
|
+
16. kapsula
|
|
75
|
+
17. kapsul
|
|
76
|
+
18. doz
|
|
77
|
+
19. doza
|
|
78
|
+
20. doze
|
|
79
|
+
21. tub
|
|
80
|
+
22. tubi
|
|
81
|
+
23. tube
|
|
82
|
+
24. tuba
|
|
83
|
+
25. ser
|
|
84
|
+
26. kos
|
|
85
|
+
27. kosov
|
|
86
|
+
28. kosa
|
|
87
|
+
29. kosi
|
|
88
|
+
30. kom
|
|
89
|
+
31. komadov
|
|
90
|
+
32. komada
|
|
91
|
+
33. komadi
|
|
92
|
+
34. komad
|
|
93
|
+
2. zamenjaj tablete, tablet, tabl, tableta, tab -> tbl
|
|
94
|
+
3. zamenjaj deci z dl
|
|
95
|
+
4. zamenjaj cap, caps, kap, kaps, kapsula, kapsul, cap -> kps
|
|
96
|
+
5. zamenjaj doza, doze -> doz
|
|
97
|
+
6. zamenjaj tube, tubi, tuba -> tub
|
|
98
|
+
7. zamenjaj kosov, kosa, kosi -> kos
|
|
99
|
+
8. zamenjaj komad, komada, komadi, komadov -> kos
|
|
100
|
+
7. ostrani pike za enotami
|
|
101
|
+
1. "100 gr." -> "100 gr."
|
|
102
|
+
8. izbriši presledke med številko in enoto / enoto
|
|
103
|
+
1. 100 mg / g => 100mg/g
|
|
104
|
+
9. izbriši presledke med številko in enoto
|
|
105
|
+
1. primer: 50.5 mg -> 50.5mg
|
|
106
|
+
2. primer: 200 mg 50 mg 10 mg -> 200mg 50mg 10mg
|
|
107
|
+
10. zamenjaj pike pred enoto s presledki
|
|
108
|
+
1. "inj.100ml" -> "inj 100ml"
|
|
109
|
+
11. izbriši pike znotraj številk, a ohrani decimalne pike
|
|
110
|
+
1. "5.000.000 i.e./ml -> "5000000ie/ml"
|
|
111
|
+
12. odstrani vse pike pred presledkom
|
|
112
|
+
13. odstrani vse pike za črkami
|
|
113
|
+
14. zamenjaj pike med črkami s presledki
|
|
114
|
+
1. ANTIPAR.ŠAMPON -> "ANTIPAR ŠAMPON"
|
|
115
|
+
15. enote gr zamenjaj z g
|
|
116
|
+
1. 10gr -> 10g
|
|
117
|
+
16. strni teže žival v kg (teže so v kg)
|
|
118
|
+
1. "od 40,1 do 60,0 kg" -> "40.1-60.0kg"
|
|
119
|
+
2. "od 40,1 kg do 60,0 kg" -> "40.1kg-60.0kg"
|
|
120
|
+
3. "nad 40,1 kg" -> "40.1kg-"
|
|
121
|
+
4. "pod 40,1 kg" -> "-40.1kg"
|
|
122
|
+
5. "do 40,1 kg" -> "-40.1kg"
|
|
123
|
+
6. "od 40kg - 60kg" -> "40-60kg"
|
|
124
|
+
7. "vsaj 40kg" -> "-40kg"
|
|
125
|
+
8. "največ 40kg" -> "-40kg"
|
|
126
|
+
9. "najmanj 5kg" -> "5kg-"
|
|
127
|
+
17. odstrani decimalke pri težah
|
|
128
|
+
1. "-40.1kg" -> "40kg"
|
|
129
|
+
2. razen, če je teža < 1kg
|
|
130
|
+
1. "0.5kg" -> "0.5kg"
|
|
131
|
+
2. "0,5 kg" -> "0.5kg"
|
|
132
|
+
18. teži dodaj kg za vsako številko
|
|
133
|
+
19. odstrani " za "
|
|
134
|
+
20. uredi količine čisto na koncu naziva
|
|
135
|
+
1. prepoznavanje
|
|
136
|
+
1. količina je na koncu naziva
|
|
137
|
+
1. izjema: količina "á+številka" ali "a+številka" se lahko pojavi tudi sredi niza
|
|
138
|
+
1. "nekaj á10 še nekaj" -> količina = 10
|
|
139
|
+
2. "nekaj a10 še nekaj" -> količina = 10
|
|
140
|
+
2. enotaKolcine je enota, razen
|
|
141
|
+
1. g, mg, mcg, kg, ml, dl, ie
|
|
142
|
+
3. količina je oblike
|
|
143
|
+
1. enotaKolcine
|
|
144
|
+
2. številka, morda presledki, enotaKolcine
|
|
145
|
+
3. a ali á + morda presledki + številka + morda enotaKolcine
|
|
146
|
+
1. "a7tbl"
|
|
147
|
+
2. "a 7tbl"
|
|
148
|
+
3. "a 7 tbl"
|
|
149
|
+
4. količina je lahko oblike številka * številka + morda enotaKolcine
|
|
150
|
+
5. količina je lahko oblike številka x številka + morda enotaKolcine
|
|
151
|
+
4. količina se lahko konča z "*"
|
|
152
|
+
2. ureditev
|
|
153
|
+
1. odstrani presledke okrog x ali *
|
|
154
|
+
2. odstrani začetni "a" ali "á" in namesto tega številki pripiši "x" na konec
|
|
155
|
+
3. za odstrani začeni x
|
|
156
|
+
1. ypozane 15mg x7tbl -> ypozane 15mg 7tbl
|
|
157
|
+
4. če je številka "1", jo odstrani
|
|
158
|
+
1. 1kom -> kom
|
|
159
|
+
21. nazivu dodaj na koncu " " in nato zamenjaj vse " / " s presledki
|
|
160
|
+
22. zamenjaj živalske vrste
|
|
161
|
+
1. psi, pse, psa -> pse
|
|
162
|
+
2. mačko, mačka, mačke -> mačke
|
|
163
|
+
3. krava, krave, telice -> govedo
|
|
164
|
+
23. zamenjaj zaporedne presledke z enim
|
|
165
|
+
24. odstrani vse znake / za presledkom
|
|
166
|
+
|
|
167
|
+
### razcleniNaziv.ts
|
|
168
|
+
|
|
169
|
+
funkcija **razcleniNaziv**:
|
|
170
|
+
1. za naziv kreiraj objekt *{ izvorni_naziv, normaliziran_naziv, teza, kolicina, doza, besede, zivalskeVrste }*
|
|
171
|
+
2. ustvari niz teža, v katerega zapišeš težo.
|
|
172
|
+
3. ostvari niz doze, v katerega zapišeš vse doze, ki so lahko kombinacija številk, enot in "/":
|
|
173
|
+
1. 100mcg
|
|
174
|
+
2. 2mg/5ml
|
|
175
|
+
3. 2x3ml
|
|
176
|
+
4. pred dozo je lahko koncentracija
|
|
177
|
+
4. ustvari string količina, v katerega prepišeš količino s konca naziva.
|
|
178
|
+
5. ustvari string[] besede iz preostalih besed izvornega naziva
|
|
179
|
+
1. iz besed odstrani in, za,
|
|
180
|
+
6. med besedami z uporabo funkcije poisciZivalskoVrsto poišči tiste, ki predstavljajo živalsko vrsto, in jih premesti v polje zivalskeVrste
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
#### oceniPodobnost
|
|
184
|
+
Funkcija **oceniPodobnost** v src/register/oceniPodobnost.ts
|
|
185
|
+
1. *export function oceniPodobnost(razclembaVhoda: RazclenjeniNaziv, zdrrazclembaRegistravilo: RazclenjeniNaziv) : UtemeljitevOcene*
|
|
186
|
+
2. vrne utemeljeno oceno podobnosti med razčlembama
|
|
187
|
+
3. implementacija
|
|
188
|
+
1. izračuna delne ocene
|
|
189
|
+
1. ocenaPrvihBesed
|
|
190
|
+
1. poišči prvo štiri besede zdravila iz razclembaRegistra
|
|
191
|
+
2. če se prve štiri besede v seznamu besed v razclembaRegistra nahajajo tudi v razclembaVhoda, točkuj
|
|
192
|
+
1. ujemanje prve besede s 500
|
|
193
|
+
2. ujemanje druge besede s 300
|
|
194
|
+
3. ujemanje tretje besede z 200
|
|
195
|
+
4. ujemanje četrte besede z 100
|
|
196
|
+
3. če se besede ne ujemajo v celoti ampak se ujema samo prvi del besed, pripiši polovične točke
|
|
197
|
+
2. ocenaVelikosti
|
|
198
|
+
1. za vsako izmed velikosti [male/mali, srednje/srednji, velike/veliki, zelo] ocenaVelikosti+=70
|
|
199
|
+
3. ocenaDoze
|
|
200
|
+
1. za vsako dozo iz razclembaVhoda, ki se nahaja v razclembaRegistra, ocenaDoze += (200 / razclembaRegistra.doze.length)
|
|
201
|
+
2. za vsako dozo iz razclembaVhoda, ki ima length>3 in je začetek neke doze iz razclembaRegistra, ocenaDoze += (100 / razclembaRegistra.doze.length)
|
|
202
|
+
4. ocenaZivalskihVrst
|
|
203
|
+
1. za vsako živalsko vrsto, ki je v razclembaRegistra in jo najdeš tudi v razclembaVhoda, ocenaZivalskihVrst += (200 / razclembaRegistra.zivalskeVrste.length)
|
|
204
|
+
5. ocenaTeze
|
|
205
|
+
1. če ima razclembaRegistra težo in je ta tudi v razclembaVhoda, ocenaTeze = 300
|
|
206
|
+
6. ocenaKolicine
|
|
207
|
+
1. če ima razclembaRegistra količino in je ta tudi v razclembaVhoda, scocenaKolicine = 200
|
|
208
|
+
7. ocenaBesed
|
|
209
|
+
1. za vsako besedo, ki se pojavlja v obeh razčlembah, scoreBesed += 10*beseda length, a skupaj največ 200
|
|
210
|
+
8. steviloBesed
|
|
211
|
+
1. razliko v številu besed oceni z -10*(razlika)
|
|
212
|
+
2. izracunajPodobnost vrne objekt delnih ocen in skupno oceno "ocena" (seštevek vseh delnih ocen)
|
|
213
|
+
|
|
214
|
+
#### uganiZdravilo.ts
|
|
215
|
+
|
|
216
|
+
Funkcija **uganiZdraviloInUtemelji** v src/register/uganiZdravilo.ts
|
|
217
|
+
1. export function uganiZdraviloInUtemelji(vhodniNaziv: string, limit=10) : { zdravilo: Zdravilo, utemeljitev: UtemeljitevOcene }[]
|
|
218
|
+
2. izračunaj in v module scope cachiraj razčlembe registra
|
|
219
|
+
1. za vsako zdravilo iz /src/generated/seznamZdravil
|
|
220
|
+
1. normaliziraj naziv
|
|
221
|
+
2. razčleni normalizirani naziv
|
|
222
|
+
3. normaliziraj in razčleni vhodni naziv
|
|
223
|
+
4. izračunaj podobnosti med razčlenjenim vhodnim nazivom in vsemi razčlenjenimi nazivi iz registra
|
|
224
|
+
5. vrni seznam "limit" najbolje ocenjenih zdravil z utemeljitvami, s tem morajo biti ocene višje od 1000, sicer zadetki ne veljajo
|
|
225
|
+
|
|
226
|
+
Funkcija **uganiZdravilo** v src/register/uganiZdravilo.ts
|
|
227
|
+
1. export function uganiZdravilo(vhodniNaziv: string, limit=10) : { zadetki: { zdravilo: Zdravilo, ocena: number }[], najboljsi: Zdravilo | undefined }
|
|
228
|
+
2. pokliče uganiZdraviloInUtemelji in vrne zadetke z ocenami
|
|
229
|
+
3. najboljsi je zdravilo, ki je edino ali ima najvišjo oceno (če sta dva z enako oceno, najboljsi ni določen)
|
|
230
|
+
|