""" entitas.py — Representasi eksplisit entitas dalam wacana AKSARA. ANTI-TRANSFORMER: Transformer: referensi anafor diselesaikan implisit via attention score. AKSARA: setiap entitas punya catatan eksplisit — nama kanonik, variasi rujukan, tipe, dan riwayat peran dalam proposisi. Ini adalah "buku catatan" entitas yang dibaca saat memproses teks — bukan hidden state yang tidak bisa diaudit. """ from __future__ import annotations from dataclasses import dataclass, field from typing import Dict, List, Optional, Set, Tuple from aksara.base.state import AksaraState from aksara.primitives.krl.proposition import Proposisi from aksara.primitives.krl.inference import Inferensi # Pronomina persona bahasa Indonesia yang memicu resolusi referensi PRONOMINA_PERSONA: Set[str] = { "dia", "ia", "beliau", "anda", "kamu", "engkau", "mereka", "kalian", "kami", "kita", "-nya", "nya", } # Demonstrativa anaforis — merujuk ke entitas yang sudah disebutkan DEMONSTRATIVA_ANAFORIS: Set[str] = { "itu", "tersebut", "tadi", "dimaksud", "ini", } # Tipe entitas yang kompatibel dengan pronomina persona TIPE_PERSONA: Set[str] = { "PERSONA", "PERSONA_OTORITAS", "PERSONA_TERDUGA", "PERSONA_KORBAN", "ORGANISASI", "INSTITUSI", } @dataclass class EntitasAktif: """ Satu entitas yang aktif dalam wacana. Setiap entitas memiliki: - nama_kanonis: bentuk kanonik yang digunakan sebagai kunci - nama_variasi: semua cara entitas ini dirujuk ("terdakwa", "dia", "tersangka") - tipe: dari TipeEntitas KRL (PERSONA, BENDA, LOKASI, dll.) - riwayat peran: di kalimat mana dan sebagai apa entitas ini muncul Contoh: nama_kanonis = "Budi" nama_variasi = {"Budi", "dia", "ia", "beliau"} peran_riwayat = [(0, "agen"), (2, "pasien")] """ nama_kanonis: str tipe: str = "ENTITAS" nama_variasi: Set[str] = field(default_factory=set) indeks_pertama: int = 0 indeks_terakhir: int = 0 peran_riwayat: List[Tuple[int, str]] = field(default_factory=list) def __post_init__(self) -> None: if self.nama_kanonis not in self.nama_variasi: self.nama_variasi.add(self.nama_kanonis) def cocok(self, nama: str) -> bool: """Apakah string ini merujuk ke entitas ini?""" return nama.lower() in {v.lower() for v in self.nama_variasi} def tambah_variasi(self, nama: str) -> None: """Tambah cara lain untuk merujuk ke entitas ini.""" self.nama_variasi.add(nama) def adalah_persona(self) -> bool: return self.tipe in TIPE_PERSONA def perbarui_kemunculan(self, indeks: int, peran: str) -> None: self.indeks_terakhir = indeks self.peran_riwayat.append((indeks, peran)) def ke_dict(self) -> dict: return { "nama_kanonis": self.nama_kanonis, "tipe": self.tipe, "nama_variasi": sorted(self.nama_variasi), "indeks_pertama": self.indeks_pertama, "indeks_terakhir": self.indeks_terakhir, "peran_riwayat": self.peran_riwayat, } @dataclass class BingkaiWacana: """ Satu bingkai dalam wacana — satu kalimat beserta seluruh state linguistiknya. Bingkai adalah unit terkecil discourse AKSARA. Berbeda dari hidden state Transformer: setiap bingkai bisa dibaca dan diaudit. """ indeks: int kalimat: str state: AksaraState proposisi: Optional[Proposisi] inferensi: List[Inferensi] = field(default_factory=list) @property def skor_linguistik(self) -> float: return self.state.skor_linguistik @property def ada_proposisi(self) -> bool: return self.proposisi is not None @property def entitas_disebutkan(self) -> List[str]: """Semua nilai slot dari proposisi kalimat ini.""" if self.proposisi is None: return [] return [s.nilai for s in self.proposisi.slot.values() if s.nilai] def ke_dict(self) -> dict: return { "indeks": self.indeks, "kalimat": self.kalimat, "skor_linguistik": self.skor_linguistik, "proposisi": self.proposisi.ke_dict() if self.proposisi else None, "n_inferensi": len(self.inferensi), }