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,100 @@
1
+ /**
2
+ * Iskanje živalskih vrst
3
+ *
4
+ * Funkcije za iskanje in ujemanje živalskih vrst iz registra.
5
+ * Uporablja _match regex iz skupneEntitete.vrsteZivali.
6
+ */
7
+
8
+ import { ZivalskeVrste } from "../types/ZivalskeVrste";
9
+
10
+ /**
11
+ * Rezultat iskanja živalske vrste
12
+ */
13
+ export interface RezultatIskanja {
14
+ /** Najdena vrsta (ključ iz ZivalskeVrste) */
15
+ vrsta: string;
16
+ /** Nadrejena vrsta, če obstaja */
17
+ nadrejenaVrsta: string | null;
18
+ }
19
+
20
+ /**
21
+ * Poišče nadrejeno živalsko vrsto za podano vrsto
22
+ * Primer: "krave v laktaciji" → "govedo", "kokoši nesnice" → "perutnina"
23
+ *
24
+ * Uporablja _match regex iz ZivalskeVrste
25
+ */
26
+ export function findNadrejenaVrsta(vrsta: string): string | null {
27
+ const vrstaLower = vrsta.toLowerCase();
28
+
29
+ for (const [key, vrstaDef] of Object.entries(ZivalskeVrste)) {
30
+ if (!vrstaDef?._match) continue;
31
+
32
+ if (vrstaDef._match.test(vrstaLower)) {
33
+ // Če ima vrsta nadrejeno vrsto (vrsta !== key), vrni nadrejeno
34
+ if (typeof vrstaDef.vrsta === "string" && vrstaDef.vrsta.toLowerCase() !== key.toLowerCase()) {
35
+ return vrstaDef.vrsta;
36
+ }
37
+ // Vrsta je že osnovni ključ - ni nadrejene
38
+ return null;
39
+ }
40
+ }
41
+
42
+ return null;
43
+ }
44
+
45
+ /**
46
+ * Poišče ustrezno živalsko vrsto za podani niz
47
+ *
48
+ * @param za - Niz za iskanje (npr. "psi", "krave v laktaciji", "kokoši nesnice")
49
+ * @returns Rezultat z najdeno vrsto in nadrejeno vrsto (če obstaja)
50
+ */
51
+ export function poisciZivalskoVrsto(za: string): RezultatIskanja | null {
52
+ if (!za || typeof za !== "string") return null;
53
+
54
+ const zaLower = za.toLowerCase().trim();
55
+ if (zaLower === "") return null;
56
+
57
+ // 1. Poskusi najti točno ujemanje po ključu
58
+ for (const [key, vrstaDef] of Object.entries(ZivalskeVrste)) {
59
+ if (key.toLowerCase() === zaLower) {
60
+ return {
61
+ vrsta: key,
62
+ nadrejenaVrsta: findNadrejenaVrsta(key),
63
+ };
64
+ }
65
+ }
66
+
67
+ // 2. Poskusi z _match regex iz ZivalskeVrste
68
+ for (const [key, vrstaDef] of Object.entries(ZivalskeVrste)) {
69
+ if (!vrstaDef?._match) continue;
70
+
71
+ if (vrstaDef._match.test(zaLower)) {
72
+ return {
73
+ vrsta: key,
74
+ nadrejenaVrsta: findNadrejenaVrsta(key),
75
+ };
76
+ }
77
+
78
+ // Poskusi tudi po lastnosti vrsta
79
+ if (typeof vrstaDef.vrsta === "string" && vrstaDef.vrsta.toLowerCase() === zaLower) {
80
+ return {
81
+ vrsta: key,
82
+ nadrejenaVrsta: findNadrejenaVrsta(key),
83
+ };
84
+ }
85
+ }
86
+
87
+ // 3. Ni ujemanja - vrni izvorni niz kot vrsto
88
+ return {
89
+ vrsta: za,
90
+ nadrejenaVrsta: null,
91
+ };
92
+ }
93
+
94
+ /**
95
+ * Normalizacija imena živalske vrste
96
+ */
97
+ export function normalizeVrsta(vrsta: string): string {
98
+ // Odstrani # znak in odvečne presledke
99
+ return vrsta.replace(/#/g, "").trim().toLowerCase();
100
+ }
@@ -0,0 +1,105 @@
1
+ import { RazclenjeniNaziv, normalizirajNaziv, KOLICINA_PATTERN, TEZA_PATTERN, DOZA_PATTERN } from "./normalizirajNaziv";
2
+ import { poisciZivalskoVrsto } from "./poisciZivalskoVrsto";
3
+ import { ZivalskeVrste } from "../types/ZivalskeVrste";
4
+
5
+ // Seznam veljavnih ključev živalskih vrst (male črke)
6
+ const VELJAVNE_VRSTE = new Set(Object.keys(ZivalskeVrste).map(k => k.toLowerCase()));
7
+
8
+ /**
9
+ * Razčleni normaliziran naziv zdravila na sestavne dele
10
+ *
11
+ * @param naziv - Izvorni naziv zdravila
12
+ * @returns Objekt z razčlenjenimi sestavinami
13
+ */
14
+
15
+ // Vzorec za prepoznavanje količine v obliki á/a + številka sredi niza
16
+ const KOLICINA_A_PATTERN = /(?<![a-zA-ZčšžćđČŠŽĆĐ])[aá]\s*(\d+)/i;
17
+
18
+ export function razcleniNaziv(naziv: string): RazclenjeniNaziv {
19
+ const izvorni_naziv = naziv;
20
+
21
+ // Pred normalizacijo poiščemo količino v obliki á/a + številka
22
+ let kolicinaIzSrediNiza: string | null = null;
23
+ const aMatch = KOLICINA_A_PATTERN.exec(naziv.toLowerCase());
24
+ if (aMatch) {
25
+ kolicinaIzSrediNiza = aMatch[1]; // Samo številka
26
+ }
27
+
28
+ const normaliziran_naziv = normalizirajNaziv(naziv);
29
+
30
+ // Razdelimo normaliziran naziv na besede
31
+ const deli = normaliziran_naziv.split(/\s+/).filter(d => d.length > 0);
32
+
33
+ let teza: string | null = null;
34
+ let kolicina: string | null = null;
35
+ const doze: string[] = [];
36
+ const besede: string[] = [];
37
+
38
+ // Preverimo, ali je zadnji del količina
39
+ if (deli.length > 0) {
40
+ const zadnji = deli[deli.length - 1];
41
+ if (KOLICINA_PATTERN.test(zadnji)) {
42
+ kolicina = zadnji;
43
+ deli.pop();
44
+ }
45
+ }
46
+
47
+ // Če ni količine na koncu, uporabi količino iz á/a vzorca sredi niza
48
+ if (!kolicina && kolicinaIzSrediNiza) {
49
+ kolicina = kolicinaIzSrediNiza;
50
+ // Odstrani to številko iz delov (normalizacija jo je pretvorila v samostojno številko)
51
+ const idx = deli.indexOf(kolicinaIzSrediNiza);
52
+ if (idx !== -1) {
53
+ deli.splice(idx, 1);
54
+ }
55
+ }
56
+
57
+ // Pregledamo preostale dele
58
+ for (const del of deli) {
59
+ // Preverimo, ali je teža
60
+ if (TEZA_PATTERN.test(del)) {
61
+ teza = del;
62
+ continue;
63
+ }
64
+
65
+ // Preverimo, ali je doza
66
+ if (DOZA_PATTERN.test(del)) {
67
+ doze.push(del);
68
+ continue;
69
+ }
70
+
71
+ // Sicer je beseda
72
+ besede.push(del);
73
+ }
74
+
75
+ // Filtriraj vezniške besede "in" in "za"
76
+ const filtriraneBesede = besede.filter(b => b !== "in" && b !== "za");
77
+
78
+ // Poišči živalske vrste med besedami
79
+ const zivalskeVrste: string[] = [];
80
+ const preostaleBesede: string[] = [];
81
+
82
+ for (const beseda of filtriraneBesede) {
83
+ const rezultat = poisciZivalskoVrsto(beseda);
84
+ // Preverimo, ali je rezultat veljavna živalska vrsta (ne izvorni niz)
85
+ if (rezultat && VELJAVNE_VRSTE.has(rezultat.vrsta.toLowerCase())) {
86
+ // Našli smo prepoznano živalsko vrsto
87
+ if (!zivalskeVrste.includes(rezultat.vrsta)) {
88
+ zivalskeVrste.push(rezultat.vrsta);
89
+ }
90
+ } else {
91
+ // Ni živalska vrsta, ohrani med besedami
92
+ preostaleBesede.push(beseda);
93
+ }
94
+ }
95
+
96
+ return {
97
+ izvorni_naziv,
98
+ normaliziran_naziv,
99
+ teza,
100
+ kolicina,
101
+ doze,
102
+ besede: preostaleBesede,
103
+ zivalskeVrste
104
+ };
105
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Test normalizacije
3
+ *
4
+ * Generira datoteki z izvornimi in normaliziranimi imeni zdravil.
5
+ */
6
+
7
+ import { parseRegister } from "../parseRegister";
8
+ import { normalizirajNaziv } from "./normalizirajNaziv";
9
+ import { razcleniNaziv } from "./razcleniNaziv";
10
+ import { poisciZivalskoVrsto } from "./poisciZivalskoVrsto";
11
+ import testData from "../../test/zdravila.json";
12
+ import { writeFileSync } from "fs";
13
+
14
+ /** Seznam znanih živalskih vrst za ujemanje */
15
+ const ZIVALSKE_VRSTE_BESEDE = [
16
+ "pse", "psi", "psa", "pes",
17
+ "mačke", "mačka", "mačko", "mačk",
18
+ "govedo", "krave", "krava", "telice", "teleta", "telet", "biki", "voli",
19
+ "konje", "konj", "konja", "konji", "žrebeta", "osle", "osli",
20
+ "prašiče", "prašič", "prašiči", "pujske", "pujski", "svinje",
21
+ "ovce", "ovca", "jagnjeta", "jagnjet", "ovni",
22
+ "koze", "koza", "kozle", "kozliče",
23
+ "kunce", "kuncev", "kunci",
24
+ "perutnina", "piščance", "piščanci", "kokoši", "purane", "purani", "race", "gosi",
25
+ "ribe", "postrvi",
26
+ "čebele", "čebel",
27
+ ];
28
+
29
+
30
+
31
+ interface ZdraviloTest {
32
+ naziv: string;
33
+ skupine: string[];
34
+ }
35
+
36
+ async function main() {
37
+ console.log("Generiranje normalizacijskih datotek...\n");
38
+
39
+ // 1. Register zdravil
40
+ console.log("Nalagam register...");
41
+ const register = parseRegister("./data/register.xlsx");
42
+ console.log(`Register naložen: ${register.steviloZdravil} zdravil\n`);
43
+
44
+ // Generiraj zdravila-register-norm.txt
45
+ const registerLines: string[] = [];
46
+ const registerImena = register.zdravila.map((z) => z.ime).sort((a, b) => a.localeCompare(b, "sl"));
47
+
48
+ for (const ime of registerImena) {
49
+ const razclenjeno = razcleniNaziv(ime);
50
+ registerLines.push(` `);
51
+ registerLines.push(`- ${ime}`);
52
+ registerLines.push(`> ${razclenjeno.normaliziran_naziv}`);
53
+ const deli: string[] = [];
54
+ if (razclenjeno.besede) deli.push(`${razclenjeno.besede}`);
55
+ if (razclenjeno.doze.length > 0) deli.push(`[ ${razclenjeno.doze.join(", ")} ]`);
56
+ if (razclenjeno.teza) deli.push(`${razclenjeno.teza}`);
57
+ if (razclenjeno.zivalskeVrste.length>0) deli.push(`[ ${razclenjeno.zivalskeVrste} ]`);
58
+ if (razclenjeno.kolicina) deli.push(`${razclenjeno.kolicina}`);
59
+ registerLines.push(`= ${deli.join(" - ")}`);
60
+ }
61
+
62
+ writeFileSync("./data/zdravila-register-norm.txt", registerLines.join("\n"), "utf-8");
63
+ console.log(`Zapisano: data/zdravila-register-norm.txt (${registerImena.length} zdravil)`);
64
+
65
+ // 2. Vhodna zdravila iz zdravila.json
66
+ const vhodZdravila = (testData as ZdraviloTest[]).map((z) => z.naziv).sort((a, b) => a.localeCompare(b, "sl"));
67
+
68
+ const vhodLines: string[] = [];
69
+ for (const naziv of vhodZdravila) {
70
+ const razclenjeno = razcleniNaziv(naziv);
71
+ vhodLines.push(` `);
72
+ vhodLines.push(`- ${naziv}`);
73
+ vhodLines.push(`> ${razclenjeno.normaliziran_naziv}`);
74
+ const deli: string[] = [];
75
+ if (razclenjeno.besede) deli.push(`${razclenjeno.besede}`);
76
+ if (razclenjeno.doze.length > 0) deli.push(`[ ${razclenjeno.doze.join(", ")} ]`);
77
+ if (razclenjeno.teza) deli.push(`${razclenjeno.teza}`);
78
+ if (razclenjeno.zivalskeVrste.length>0) deli.push(`[ ${razclenjeno.zivalskeVrste} ]`);
79
+ if (razclenjeno.kolicina) deli.push(`${razclenjeno.kolicina}`);
80
+ vhodLines.push(`= ${deli.join(" - ")}`);
81
+ }
82
+
83
+ writeFileSync("./data/zdravila-vhod-norm.txt", vhodLines.join("\n"), "utf-8");
84
+ console.log(`Zapisano: data/zdravila-vhod-norm.txt (${vhodZdravila.length} zdravil)`);
85
+
86
+ console.log("\nKončano!");
87
+ }
88
+
89
+ main();
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Test podobnosti - preverja, ali oceniPodobnost pravilno prepozna zdravila
3
+ *
4
+ * Za vsako zdravilo iz registra preveri, ali se pri iskanju samega sebe
5
+ * zdravilo pojavi na prvem mestu.
6
+ */
7
+
8
+ import { razcleniNaziv } from "./razcleniNaziv";
9
+ import { oceniPodobnost, type UtemeljitevOcene } from "./oceniPodobnost";
10
+ import { seznamZdravil } from "../../generated/seznamZdravil"
11
+ import type { RazclenjeniNaziv } from "./normalizirajNaziv";
12
+
13
+ interface RazclembaZdravila {
14
+ ime: string;
15
+ razclemba: RazclenjeniNaziv;
16
+ }
17
+
18
+ // Predpripravi razčlembe vseh zdravil iz registra
19
+ function pripraviRazclembeRegistra(): RazclembaZdravila[] {
20
+ return seznamZdravil.map((zdravilo) => ({
21
+ ime: zdravilo.ime,
22
+ razclemba: razcleniNaziv(zdravilo.ime),
23
+ }));
24
+ }
25
+
26
+ interface RezultatIskanja {
27
+ ime: string;
28
+ ocena: number;
29
+ }
30
+
31
+ // Poišči najboljša ujemanja za dano razčlembo
32
+ function poisciNajboljsa(
33
+ razclembaVhoda: RazclenjeniNaziv,
34
+ razclembeRegistra: RazclembaZdravila[]
35
+ ): RezultatIskanja[] {
36
+ const rezultati: RezultatIskanja[] = [];
37
+
38
+ for (const { ime, razclemba } of razclembeRegistra) {
39
+ const utemeljitev = oceniPodobnost(razclembaVhoda, razclemba);
40
+ rezultati.push({ ime, ocena: utemeljitev.ocena });
41
+ }
42
+
43
+ // Sortiraj po oceni padajoče
44
+ rezultati.sort((a, b) => b.ocena - a.ocena);
45
+
46
+ return rezultati;
47
+ }
48
+
49
+ interface Statistika {
50
+ // Natanko en zadetek z najvišjo oceno
51
+ enZadetek: number;
52
+ // Več zadetkov z enako najvišjo oceno, prvi je pravi
53
+ vecPrviPravi: number;
54
+ // Več zadetkov z enako najvišjo oceno, pravi je med njimi (a ni prvi)
55
+ vecPraviMedNjimi: number;
56
+ // Pravi ni med zadetki z najvišjo oceno
57
+ niZadetka: number;
58
+ // Skupaj
59
+ skupaj: number;
60
+ }
61
+
62
+ interface NajdeniZadetek {
63
+ ime: string;
64
+ razclemba: RazclenjeniNaziv;
65
+ utemeljitev: UtemeljitevOcene;
66
+ }
67
+
68
+ interface VecPraviMedNjimiPrimer {
69
+ iskaniNaziv: string;
70
+ iskanaRazclemba: RazclenjeniNaziv;
71
+ najdeniDoVkljucnoPravega: NajdeniZadetek[];
72
+ }
73
+
74
+ function izpisiRazclembo(razclemba: RazclenjeniNaziv): string {
75
+ const deli: string[] = [];
76
+ if (razclemba.besede.length > 0) deli.push(`besede: [${razclemba.besede.join(", ")}]`);
77
+ if (razclemba.doze.length > 0) deli.push(`doze: [${razclemba.doze.join(", ")}]`);
78
+ if (razclemba.teza) deli.push(`teza: ${razclemba.teza}`);
79
+ if (razclemba.kolicina) deli.push(`kolicina: ${razclemba.kolicina}`);
80
+ if (razclemba.zivalskeVrste.length > 0) deli.push(`zivalskeVrste: [${razclemba.zivalskeVrste.join(", ")}]`);
81
+ return deli.join(", ");
82
+ }
83
+
84
+ function izpisiUtemeljitev(u: UtemeljitevOcene): string {
85
+ const deli: string[] = [];
86
+ deli.push(`ocena: ${u.ocena}`);
87
+ if (u.ocenaPrvihBesed > 0) deli.push(`prveBesede: ${u.ocenaPrvihBesed}`);
88
+ if (u.ocenaVelikosti > 0) deli.push(`velikost: ${u.ocenaVelikosti}`);
89
+ if (u.ocenaDoze > 0) deli.push(`doze: ${u.ocenaDoze}`);
90
+ if (u.ocenaTeze > 0) deli.push(`teza: ${u.ocenaTeze}`);
91
+ if (u.ocenaKolicine > 0) deli.push(`kolicina: ${u.ocenaKolicine}`);
92
+ if (u.ocenaZivalskihVrst > 0) deli.push(`zivalske: ${u.ocenaZivalskihVrst}`);
93
+ if (u.ocenaBesed > 0) deli.push(`besede: ${u.ocenaBesed}`);
94
+ if (u.steviloBesed !== 0) deli.push(`štBesed: ${u.steviloBesed}`);
95
+ return deli.join(", ");
96
+ }
97
+
98
+ async function main() {
99
+ console.log("═══════════════════════════════════════════════════════════════");
100
+ console.log(" TEST PODOBNOSTI");
101
+ console.log("═══════════════════════════════════════════════════════════════\n");
102
+
103
+ console.log("Pripravljam razčlembe registra...");
104
+ const razclembeRegistra = pripraviRazclembeRegistra();
105
+ console.log(`Pripravljenih ${razclembeRegistra.length} razčlemb.\n`);
106
+
107
+ const statistika: Statistika = {
108
+ enZadetek: 0,
109
+ vecPrviPravi: 0,
110
+ vecPraviMedNjimi: 0,
111
+ niZadetka: 0,
112
+ skupaj: 0,
113
+ };
114
+
115
+ const napake: string[] = [];
116
+ const vecPraviMedNjimiPrimeri: VecPraviMedNjimiPrimer[] = [];
117
+
118
+ console.log("Testiram podobnosti...\n");
119
+
120
+ for (const { ime, razclemba } of razclembeRegistra) {
121
+ statistika.skupaj++;
122
+
123
+ // Poišči najboljša ujemanja
124
+ const rezultati = poisciNajboljsa(razclemba, razclembeRegistra);
125
+
126
+ if (rezultati.length === 0) {
127
+ statistika.niZadetka++;
128
+ napake.push(`[NI ZADETKA] ${ime}`);
129
+ continue;
130
+ }
131
+
132
+ const najvisjaOcena = rezultati[0].ocena;
133
+
134
+ // Poišči vse z najvišjo oceno
135
+ const najboljsi = rezultati.filter((r) => r.ocena === najvisjaOcena);
136
+
137
+ // Preveri, ali je pravi med najboljšimi
138
+ const praviIndex = najboljsi.findIndex((r) => r.ime === ime);
139
+
140
+ if (najboljsi.length === 1) {
141
+ // Natanko en zadetek
142
+ if (najboljsi[0].ime === ime) {
143
+ statistika.enZadetek++;
144
+ } else {
145
+ statistika.niZadetka++;
146
+ napake.push(`[NAPAČEN ZADETEK] ${ime} -> ${najboljsi[0].ime}`);
147
+ }
148
+ } else if (praviIndex === 0) {
149
+ // Več zadetkov, prvi je pravi
150
+ statistika.vecPrviPravi++;
151
+ } else if (praviIndex > 0) {
152
+ // Več zadetkov, pravi je med njimi (a ni prvi)
153
+ // Preveri, ali imajo vsi zadetki pred pravim enak normaliziran naziv (podvojeno zdravilo)
154
+ const normaliziranNaziv = razclemba.normaliziran_naziv;
155
+ const vsiEnaki = najboljsi.slice(0, praviIndex + 1).every((r) => {
156
+ const rRazclemba = razclembeRegistra.find((reg) => reg.ime === r.ime)!.razclemba;
157
+ return rRazclemba.normaliziran_naziv === normaliziranNaziv;
158
+ });
159
+
160
+ if (vsiEnaki) {
161
+ // Podvojeno zdravilo - štejemo kot en zadetek
162
+ statistika.enZadetek++;
163
+ } else {
164
+ statistika.vecPraviMedNjimi++;
165
+ // Zberi vse zadetke do vključno pravega
166
+ const najdeniDoVkljucnoPravega: NajdeniZadetek[] = [];
167
+ for (let i = 0; i <= praviIndex; i++) {
168
+ const najdeniIme = najboljsi[i].ime;
169
+ const najdenaRazclemba = razclembeRegistra.find((r) => r.ime === najdeniIme)!.razclemba;
170
+ const utemeljitev = oceniPodobnost(razclemba, najdenaRazclemba);
171
+ najdeniDoVkljucnoPravega.push({ ime: najdeniIme, razclemba: najdenaRazclemba, utemeljitev });
172
+ }
173
+ vecPraviMedNjimiPrimeri.push({ iskaniNaziv: ime, iskanaRazclemba: razclemba, najdeniDoVkljucnoPravega });
174
+ }
175
+ } else {
176
+ // Pravi ni med zadetki z najvišjo oceno
177
+ statistika.niZadetka++;
178
+ napake.push(`[NI MED NAJBOLJŠIMI] ${ime} (najboljši: ${najboljsi.slice(0, 3).map((r) => r.ime).join(", ")})`);
179
+ }
180
+ }
181
+
182
+ // Izpis statistike
183
+ console.log("═══════════════════════════════════════════════════════════════");
184
+ console.log(" STATISTIKA");
185
+ console.log("═══════════════════════════════════════════════════════════════\n");
186
+
187
+ const pct = (n: number) => ((n / statistika.skupaj) * 100).toFixed(1);
188
+
189
+ console.log(`Skupaj zdravil: ${statistika.skupaj}`);
190
+ console.log(`Natanko en zadetek: ${statistika.enZadetek} (${pct(statistika.enZadetek)}%)`);
191
+ console.log(`Več zadetkov, prvi je pravi: ${statistika.vecPrviPravi} (${pct(statistika.vecPrviPravi)}%)`);
192
+ console.log(`Več zadetkov, pravi je med njimi: ${statistika.vecPraviMedNjimi} (${pct(statistika.vecPraviMedNjimi)}%)`);
193
+ console.log(`Ni zadetka / napačen zadetek: ${statistika.niZadetka} (${pct(statistika.niZadetka)}%)`);
194
+
195
+ const uspesnost = statistika.enZadetek + statistika.vecPrviPravi + statistika.vecPraviMedNjimi;
196
+ console.log(`\nUspešnost (pravi med zadetki): ${uspesnost} (${pct(uspesnost)}%)`);
197
+
198
+ if (napake.length > 0) {
199
+ console.log("\n═══════════════════════════════════════════════════════════════");
200
+ console.log(" NAPAKE");
201
+ console.log("═══════════════════════════════════════════════════════════════\n");
202
+ for (const napaka of napake.slice(0, 20)) {
203
+ console.log(napaka);
204
+ }
205
+ if (napake.length > 20) {
206
+ console.log(`... in še ${napake.length - 20} napak`);
207
+ }
208
+ }
209
+
210
+ if (vecPraviMedNjimiPrimeri.length > 0) {
211
+ console.log("\n═══════════════════════════════════════════════════════════════");
212
+ console.log(" VEČ ZADETKOV, PRAVI JE MED NJIMI");
213
+ console.log("═══════════════════════════════════════════════════════════════");
214
+ for (const primer of vecPraviMedNjimiPrimeri) {
215
+ console.log("");
216
+ console.log(primer.iskaniNaziv);
217
+ console.log("=".repeat(primer.iskaniNaziv.length));
218
+ console.log(` iskana razčlemba: ${izpisiRazclembo(primer.iskanaRazclemba)}`);
219
+ console.log("");
220
+ for (const zadetek of primer.najdeniDoVkljucnoPravega) {
221
+ console.log(zadetek.ime);
222
+ console.log(` razčlemba: ${izpisiRazclembo(zadetek.razclemba)}`);
223
+ console.log(` utemeljitev: ${izpisiUtemeljitev(zadetek.utemeljitev)}`);
224
+ }
225
+ }
226
+ }
227
+
228
+ console.log("\n═══════════════════════════════════════════════════════════════");
229
+ console.log(" KONČANO");
230
+ console.log("═══════════════════════════════════════════════════════════════\n");
231
+ }
232
+
233
+ if (import.meta.main) {
234
+ main().catch((e) => {
235
+ console.error("Napaka:", e);
236
+ process.exit(1);
237
+ });
238
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Pregled vakcin v registru zdravil
3
+ *
4
+ * Izpiše vse vakcine iz registra in proti katerim boleznim ščitijo.
5
+ */
6
+
7
+ import { seznamZdravil } from "../../generated/seznamZdravil";
8
+ import { zdraviloJeVakcinaZa, jeVakcina } from "../zdraviloJeVakcinaZa";
9
+
10
+ function main() {
11
+ console.log("═══════════════════════════════════════════════════════════════");
12
+ console.log(" PREGLED VAKCIN V REGISTRU ZDRAVIL");
13
+ console.log("═══════════════════════════════════════════════════════════════\n");
14
+
15
+ // Poišči vse vakcine
16
+ const vakcine = seznamZdravil.filter((z) => jeVakcina(z));
17
+
18
+ console.log(`Skupaj vakcin v registru: ${vakcine.length}\n`);
19
+
20
+ // Razvrsti po boleznih
21
+ const poBoleznih: Record<string, { ime: string; atcKoda: string }[]> = {};
22
+
23
+ for (const zdravilo of vakcine) {
24
+ const bolezni = zdraviloJeVakcinaZa(zdravilo);
25
+ if (bolezni) {
26
+ for (const bolezen of bolezni) {
27
+ if (!poBoleznih[bolezen]) {
28
+ poBoleznih[bolezen] = [];
29
+ }
30
+ poBoleznih[bolezen].push({
31
+ ime: zdravilo.ime,
32
+ atcKoda: zdravilo.atcKoda || "-",
33
+ });
34
+ }
35
+ }
36
+ }
37
+
38
+ // Izpis po boleznih (sortirano po številu vakcin)
39
+ const sortiraneBolezni = Object.keys(poBoleznih).sort(
40
+ (a, b) => poBoleznih[b].length - poBoleznih[a].length
41
+ );
42
+
43
+ for (const bolezen of sortiraneBolezni) {
44
+ const seznam = poBoleznih[bolezen];
45
+ console.log("───────────────────────────────────────────────────────────────");
46
+ console.log(`${bolezen.toUpperCase()} (${seznam.length})`);
47
+ console.log("───────────────────────────────────────────────────────────────\n");
48
+
49
+ for (const z of seznam) {
50
+ console.log(` [${z.atcKoda}] ${z.ime}`);
51
+ }
52
+ console.log();
53
+ }
54
+
55
+ // Statistika
56
+ console.log("═══════════════════════════════════════════════════════════════");
57
+ console.log(" STATISTIKA");
58
+ console.log("═══════════════════════════════════════════════════════════════\n");
59
+
60
+ console.log(` Skupaj vakcin: ${vakcine.length}`);
61
+ console.log(` Število različnih bolezni: ${sortiraneBolezni.length}\n`);
62
+
63
+ console.log(" Po boleznih:");
64
+ for (const bolezen of sortiraneBolezni) {
65
+ const stevilo = poBoleznih[bolezen].length;
66
+ console.log(` ${bolezen}: ${stevilo}`);
67
+ }
68
+
69
+ // ATC statistika
70
+ console.log("\n───────────────────────────────────────────────────────────────");
71
+ console.log("PO ATC KATEGORIJAH");
72
+ console.log("───────────────────────────────────────────────────────────────\n");
73
+
74
+ const poAtc: Record<string, number> = {};
75
+ for (const z of vakcine) {
76
+ const prefix = z.atcKoda?.substring(0, 4) || "BREZ";
77
+ poAtc[prefix] = (poAtc[prefix] || 0) + 1;
78
+ }
79
+
80
+ const atcOpisi: Record<string, string> = {
81
+ QI01: "Ptice (perutnina)",
82
+ QI02: "Govedo",
83
+ QI04: "Ovce in koze",
84
+ QI05: "Prašiči",
85
+ QI06: "Konji",
86
+ QI07: "Psi",
87
+ QI08: "Mačke",
88
+ QI09: "Več vrst / kombinirane",
89
+ QI20: "Druge vakcine",
90
+ };
91
+
92
+ const sortiraniAtc = Object.keys(poAtc).sort();
93
+ for (const atc of sortiraniAtc) {
94
+ const opis = atcOpisi[atc] || "";
95
+ console.log(` ${atc}: ${poAtc[atc]} ${opis ? `(${opis})` : ""}`);
96
+ }
97
+
98
+ console.log("\n═══════════════════════════════════════════════════════════════\n");
99
+ }
100
+
101
+ if (import.meta.main) {
102
+ main();
103
+ }