公開前の確認用サイト
日常訳NICHIJOYAKUEnglish ↗

OPEN SOURCE

software/src/context/cross_references.py

このサイトで読み、必要なファイルを保存できます。

日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。

← オープンソースの案内へ

software/src/context/cross_references.py435 行このファイルを保存 ↓

ZIPに含まれるものと同じ公開ソースです。行番号から、その行へのリンクを保存できます。

ファイルの確認情報SHA-256 4cb8b05eb13836abc5142289963599034022eb1eac5de9ae58f69775b2eb0b0c
1"""Cross-reference system for intertextual awareness in translation.23Provides biblical cross-references to help translators understand4quotations, allusions, and thematic connections between passages.5"""67from __future__ import annotations89import json10from enum import Enum11from pathlib import Path12from typing import TYPE_CHECKING1314from pydantic import BaseModel, Field1516if TYPE_CHECKING:17    from src.models.verse import Verse, VerseReference181920class ReferenceType(str, Enum):21    """Type of cross-reference relationship."""2223    QUOTATION = "quotation"  # Direct quote from another passage24    ALLUSION = "allusion"  # Indirect reference or echo25    PARALLEL = "parallel"  # Synoptic parallel (same event/teaching)26    THEMATIC = "thematic"  # Thematic connection27    FULFILLMENT = "fulfillment"  # Prophecy fulfillment28    TYPOLOGY = "typology"  # Type/antitype relationship293031class CrossReference(BaseModel):32    """A cross-reference between two biblical passages."""3334    source_book: str = Field(..., description="Source book name")35    source_chapter: int = Field(..., ge=1)36    source_verse: int = Field(..., ge=1)37    target_book: str = Field(..., description="Target book name")38    target_chapter: int = Field(..., ge=1)39    target_verse_start: int = Field(..., ge=1)40    target_verse_end: int | None = Field(None, ge=1, description="End verse for ranges")41    reference_type: ReferenceType = Field(42        default=ReferenceType.THEMATIC,43        description="Type of cross-reference",44    )45    note: str | None = Field(None, description="Explanation of the connection")46    translation_hint: str | None = Field(47        None,48        description="Suggestion for maintaining consistency with target passage",49    )5051    @property52    def source_ref(self) -> str:53        """Get source reference string."""54        return f"{self.source_book} {self.source_chapter}:{self.source_verse}"5556    @property57    def target_ref(self) -> str:58        """Get target reference string."""59        if self.target_verse_end and self.target_verse_end != self.target_verse_start:60            return f"{self.target_book} {self.target_chapter}:{self.target_verse_start}-{self.target_verse_end}"61        return f"{self.target_book} {self.target_chapter}:{self.target_verse_start}"626364class CrossReferenceMatch(BaseModel):65    """A matched cross-reference with additional context."""6667    reference: CrossReference68    target_text: str | None = Field(None, description="Text of the target passage")69    target_translation: str | None = Field(70        None, description="Existing translation of target (if available)"71    )72    relevance_score: float = Field(73        default=1.0,74        ge=0.0,75        le=1.0,76        description="Relevance score (1.0 = most relevant)",77    )787980class CrossReferenceManager:81    """Manages biblical cross-references for translation context.8283    Provides cross-reference lookup and formatting for inclusion in84    translation prompts to ensure consistency across related passages.85    """8687    def __init__(self, data_dir: Path | str | None = None) -> None:88        """Initialize the cross-reference manager.8990        Args:91            data_dir: Path to data directory containing cross-reference files.92        """93        self._references: list[CrossReference] = []94        self._by_source: dict[str, list[CrossReference]] = {}95        self._by_target: dict[str, list[CrossReference]] = {}9697        if data_dir:98            self._data_dir = Path(data_dir)99            self._load_cross_references()100        else:101            self._data_dir = None102103    def _load_cross_references(self) -> None:104        """Load cross-references from data files."""105        if not self._data_dir:106            return107108        xref_path = self._data_dir / "metadata" / "cross_references.json"109        if not xref_path.exists():110            return111112        with xref_path.open("r", encoding="utf-8") as f:113            data = json.load(f)114115        for entry in data.get("references", []):116            ref = CrossReference(**entry)117            self.add_reference(ref)118119    def add_reference(self, ref: CrossReference) -> None:120        """Add a cross-reference to the index.121122        Args:123            ref: The cross-reference to add.124        """125        self._references.append(ref)126127        # Index by source128        source_key = f"{ref.source_book}:{ref.source_chapter}:{ref.source_verse}"129        if source_key not in self._by_source:130            self._by_source[source_key] = []131        self._by_source[source_key].append(ref)132133        # Index by target134        target_key = f"{ref.target_book}:{ref.target_chapter}:{ref.target_verse_start}"135        if target_key not in self._by_target:136            self._by_target[target_key] = []137        self._by_target[target_key].append(ref)138139    def find_references_for_verse(140        self,141        book: str,142        chapter: int,143        verse: int,144    ) -> list[CrossReference]:145        """Find all cross-references for a given verse.146147        Args:148            book: Book name.149            chapter: Chapter number.150            verse: Verse number.151152        Returns:153            List of cross-references where this verse is the source.154        """155        key = f"{book.lower()}:{chapter}:{verse}"156        return list(self._by_source.get(key, []))157158    def find_references_to_verse(159        self,160        book: str,161        chapter: int,162        verse: int,163    ) -> list[CrossReference]:164        """Find all references that point TO this verse.165166        Args:167            book: Book name.168            chapter: Chapter number.169            verse: Verse number.170171        Returns:172            List of cross-references where this verse is the target.173        """174        key = f"{book.lower()}:{chapter}:{verse}"175        return list(self._by_target.get(key, []))176177    def find_references_by_type(178        self,179        book: str,180        chapter: int,181        verse: int,182        ref_type: ReferenceType,183    ) -> list[CrossReference]:184        """Find cross-references of a specific type for a verse.185186        Args:187            book: Book name.188            chapter: Chapter number.189            verse: Verse number.190            ref_type: Type of reference to filter by.191192        Returns:193            List of matching cross-references.194        """195        refs = self.find_references_for_verse(book, chapter, verse)196        return [r for r in refs if r.reference_type == ref_type]197198    def get_quotation_sources(199        self,200        book: str,201        chapter: int,202        verse: int,203    ) -> list[CrossReference]:204        """Get OT quotation sources for a verse.205206        Particularly useful for NT verses that quote the OT.207208        Args:209            book: Book name.210            chapter: Chapter number.211            verse: Verse number.212213        Returns:214            List of quotation cross-references.215        """216        return self.find_references_by_type(217            book, chapter, verse, ReferenceType.QUOTATION218        )219220    def get_parallel_passages(221        self,222        book: str,223        chapter: int,224        verse: int,225    ) -> list[CrossReference]:226        """Get synoptic parallel passages for a verse.227228        Useful for ensuring consistency across Gospel parallels.229230        Args:231            book: Book name.232            chapter: Chapter number.233            verse: Verse number.234235        Returns:236            List of parallel passage cross-references.237        """238        return self.find_references_by_type(239            book, chapter, verse, ReferenceType.PARALLEL240        )241242    def format_for_prompt(243        self,244        references: list[CrossReference],245        include_hints: bool = True,246        max_references: int = 5,247    ) -> str:248        """Format cross-references for inclusion in a translation prompt.249250        Args:251            references: List of cross-references to format.252            include_hints: Whether to include translation hints.253            max_references: Maximum number of references to include.254255        Returns:256            Formatted string for prompt inclusion.257        """258        if not references:259            return ""260261        lines = ["CROSS-REFERENCES:"]262263        # Sort by relevance (quotations first, then type)264        type_priority = {265            ReferenceType.QUOTATION: 0,266            ReferenceType.FULFILLMENT: 1,267            ReferenceType.PARALLEL: 2,268            ReferenceType.ALLUSION: 3,269            ReferenceType.TYPOLOGY: 4,270            ReferenceType.THEMATIC: 5,271        }272        sorted_refs = sorted(273            references,274            key=lambda r: type_priority.get(r.reference_type, 99),275        )276277        for ref in sorted_refs[:max_references]:278            type_label = ref.reference_type.value.upper()279            lines.append(f"\n[{type_label}] {ref.target_ref}")280281            if ref.note:282                lines.append(f"  Note: {ref.note}")283284            if include_hints and ref.translation_hint:285                lines.append(f"  Translation hint: {ref.translation_hint}")286287        return "\n".join(lines)288289    def get_translation_consistency_notes(290        self,291        book: str,292        chapter: int,293        verse: int,294    ) -> list[str]:295        """Get notes about translation consistency for related passages.296297        Args:298            book: Book name.299            chapter: Chapter number.300            verse: Verse number.301302        Returns:303            List of consistency notes.304        """305        notes = []306307        # Check for quotations308        quotations = self.get_quotation_sources(book, chapter, verse)309        if quotations:310            for q in quotations:311                notes.append(312                    f"This verse quotes {q.target_ref}. "313                    f"Consider maintaining consistency with the source passage."314                )315                if q.translation_hint:316                    notes.append(f"Hint: {q.translation_hint}")317318        # Check for parallels319        parallels = self.get_parallel_passages(book, chapter, verse)320        if parallels:321            parallel_refs = [p.target_ref for p in parallels]322            notes.append(323                f"Synoptic parallels: {', '.join(parallel_refs)}. "324                f"Consider consistent phrasing for shared material."325            )326327        return notes328329    def save(self, path: Path | None = None) -> None:330        """Save cross-references to file.331332        Args:333            path: Path to save to. Uses default if not provided.334        """335        if path is None:336            if self._data_dir is None:337                raise ValueError("No data directory configured")338            path = self._data_dir / "metadata" / "cross_references.json"339340        path.parent.mkdir(parents=True, exist_ok=True)341342        data = {343            "version": "1.0",344            "references": [ref.model_dump() for ref in self._references],345        }346347        with path.open("w", encoding="utf-8") as f:348            json.dump(data, f, indent=2, ensure_ascii=False)349350    def __len__(self) -> int:351        """Get the number of cross-references."""352        return len(self._references)353354355# Well-known cross-references for John's Gospel (examples)356JOHN_CROSS_REFERENCES = [357    CrossReference(358        source_book="john",359        source_chapter=1,360        source_verse=1,361        target_book="genesis",362        target_chapter=1,363        target_verse_start=1,364        reference_type=ReferenceType.ALLUSION,365        note="John's opening 'In the beginning' (Ἐν ἀρχῇ) deliberately echoes Genesis",366        translation_hint="Consider using similar phrasing to Genesis 1:1 (初めに)",367    ),368    CrossReference(369        source_book="john",370        source_chapter=1,371        source_verse=14,372        target_book="exodus",373        target_chapter=33,374        target_verse_start=7,375        target_verse_end=11,376        reference_type=ReferenceType.TYPOLOGY,377        note="'Tabernacled among us' (ἐσκήνωσεν) echoes the tabernacle/tent of meeting",378        translation_hint="The word 'dwelt' has tabernacle imagery",379    ),380    CrossReference(381        source_book="john",382        source_chapter=1,383        source_verse=23,384        target_book="isaiah",385        target_chapter=40,386        target_verse_start=3,387        reference_type=ReferenceType.QUOTATION,388        note="John the Baptist quotes Isaiah 40:3",389        translation_hint="Match LXX/Isaiah translation for 'voice crying in the wilderness'",390    ),391    CrossReference(392        source_book="john",393        source_chapter=1,394        source_verse=29,395        target_book="exodus",396        target_chapter=12,397        target_verse_start=1,398        target_verse_end=13,399        reference_type=ReferenceType.TYPOLOGY,400        note="'Lamb of God' connects to Passover lamb",401        translation_hint="神の小羊 - maintain lamb imagery consistent with Passover",402    ),403    CrossReference(404        source_book="john",405        source_chapter=3,406        source_verse=14,407        target_book="numbers",408        target_chapter=21,409        target_verse_start=8,410        target_verse_end=9,411        reference_type=ReferenceType.TYPOLOGY,412        note="Bronze serpent lifted up prefigures Christ's crucifixion",413        translation_hint="Use 上げる for 'lifted up' consistently",414    ),415]416417418def create_default_cross_references(data_dir: Path) -> CrossReferenceManager:419    """Create a CrossReferenceManager with default NT cross-references.420421    Args:422        data_dir: Data directory path.423424    Returns:425        CrossReferenceManager with pre-loaded references.426    """427    manager = CrossReferenceManager(data_dir)428429    # Add well-known references if not already loaded430    if len(manager) == 0:431        for ref in JOHN_CROSS_REFERENCES:432            manager.add_reference(ref)433434    return manager435