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.
Files changed (84) hide show
  1. package/.claude/settings.local.json +17 -0
  2. package/CLAUDE.md +82 -0
  3. package/LICENSE.md +16 -0
  4. package/README.md +376 -0
  5. package/a.txt +1643 -0
  6. package/bun.lock +197 -0
  7. package/dist/atcvet/opisATCvetKode.d.ts +23 -0
  8. package/dist/atcvet/podatkiATCvetKode.d.ts +20 -0
  9. package/dist/atcvet/pomeniNivojevATCvet.d.ts +1 -0
  10. package/dist/atcvet/types/AtcvetFile.d.ts +19 -0
  11. package/dist/generated/AtcVet.d.ts +9 -0
  12. package/dist/generated/RegisterZdravil.d.ts +8 -0
  13. package/dist/generated/seznamZdravil.d.ts +8 -0
  14. package/dist/index.d.ts +244 -0
  15. package/dist/index.js +141786 -0
  16. package/dist/register/MIN_OCENA_PODOBNOSTI.d.ts +2 -0
  17. package/dist/register/helper/normalizirajNaziv.d.ts +176 -0
  18. package/dist/register/helper/oblikujRezultatIskanja.d.ts +8 -0
  19. package/dist/register/helper/oceniPodobnost.d.ts +37 -0
  20. package/dist/register/helper/poisciZivalskoVrsto.d.ts +33 -0
  21. package/dist/register/helper/razcleniNaziv.d.ts +2 -0
  22. package/dist/register/podobnaZdravilaPoATC.d.ts +16 -0
  23. package/dist/register/podobnaZdravilaPoUcinkovinah.d.ts +18 -0
  24. package/dist/register/registerZdravil.d.ts +9 -0
  25. package/dist/register/types/KarencaZdravila.d.ts +24 -0
  26. package/dist/register/types/PotUporabeZdravila.d.ts +21 -0
  27. package/dist/register/types/RazclembaZdravila.d.ts +9 -0
  28. package/dist/register/types/RegisterZdravil.d.ts +2 -0
  29. package/dist/register/types/UcinkovinaZdravila.d.ts +20 -0
  30. package/dist/register/types/Zdravilo.d.ts +65 -0
  31. package/dist/register/types/ZdraviloZUtemeljitvijo.d.ts +9 -0
  32. package/dist/register/types/ZivalskeVrste.d.ts +158 -0
  33. package/dist/register/uganiZdravilo.d.ts +43 -0
  34. package/dist/register/zdravilaZaAtcVetKodo.d.ts +8 -0
  35. package/dist/register/zdraviloJeVakcinaZa.d.ts +18 -0
  36. package/docs/vakcine.md +195 -0
  37. package/package.json +39 -0
  38. package/src/atcvet/CLAUDE.md +18 -0
  39. package/src/atcvet/downloadLatestAtcvetPdf.ts +107 -0
  40. package/src/atcvet/opisATCvetKode.ts +116 -0
  41. package/src/atcvet/parseAtcvetPdf.ts +215 -0
  42. package/src/atcvet/podatkiATCvetKode.ts +34 -0
  43. package/src/atcvet/pomeniNivojevATCvet.ts +8 -0
  44. package/src/atcvet/types/AtcvetFile.ts +22 -0
  45. package/src/generate.ts +111 -0
  46. package/src/generated/AtcVet.ts +56704 -0
  47. package/src/generated/seznamZdravil.ts +44833 -0
  48. package/src/importParseAndBuildAll.ts +97 -0
  49. package/src/index.ts +289 -0
  50. package/src/interactive.ts +428 -0
  51. package/src/register/CLAUDE.md +230 -0
  52. package/src/register/MIN_OCENA_PODOBNOSTI.ts +3 -0
  53. package/src/register/downloadRegister.ts +148 -0
  54. package/src/register/helper/analizaVakcin.ts +90 -0
  55. package/src/register/helper/checkVrste.ts +72 -0
  56. package/src/register/helper/hashString.ts +27 -0
  57. package/src/register/helper/normalizirajNaziv.ts +493 -0
  58. package/src/register/helper/oblikujRezultatIskanja.ts +15 -0
  59. package/src/register/helper/oceniPodobnost.ts +194 -0
  60. package/src/register/helper/poisciZivalskoVrsto.ts +100 -0
  61. package/src/register/helper/razcleniNaziv.ts +105 -0
  62. package/src/register/helper/testNormalizacije.ts +89 -0
  63. package/src/register/helper/testPodobnosti.ts +238 -0
  64. package/src/register/helper/testVakcin.ts +103 -0
  65. package/src/register/parseRegister.ts +464 -0
  66. package/src/register/podobnaZdravilaPoATC.ts +71 -0
  67. package/src/register/podobnaZdravilaPoUcinkovinah.ts +136 -0
  68. package/src/register/registerZdravil.ts +22 -0
  69. package/src/register/stats.ts +114 -0
  70. package/src/register/types/KarencaZdravila.ts +26 -0
  71. package/src/register/types/PotUporabeZdravila.ts +21 -0
  72. package/src/register/types/RazclembaZdravila.ts +10 -0
  73. package/src/register/types/RegisterRaw.ts +23 -0
  74. package/src/register/types/RegisterZdravil.ts +3 -0
  75. package/src/register/types/UcinkovinaZdravila.ts +21 -0
  76. package/src/register/types/Zdravilo.ts +84 -0
  77. package/src/register/types/ZdraviloZUtemeljitvijo.ts +11 -0
  78. package/src/register/types/ZivalskeVrste.ts +7 -0
  79. package/src/register/uganiZdravilo.ts +142 -0
  80. package/src/register/zdravilaZaAtcVetKodo.ts +28 -0
  81. package/src/register/zdraviloJeVakcinaZa.ts +202 -0
  82. package/src/test/testPodobnosti.test.ts +126 -0
  83. package/src/test/zdravila.json +38693 -0
  84. 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
+
@@ -0,0 +1,3 @@
1
+ /** Minimalna ocena za veljaven zadetek */
2
+
3
+ export const MIN_OCENA_PODOBNOSTI = 500;