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,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
|
+
}
|