OPEN SOURCE
software/src/data/loader.py
このサイトで読み、必要なファイルを保存できます。
日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。
1"""Data loading utilities for Bible source texts."""23from __future__ import annotations45import json6from pathlib import Path7from typing import Any89from src.data.migrations import load_glossary_any_version10from src.models.verse import (11BookMetadata,12ChapterSummary,13GlossaryTerm,14Verse,15VerseReference,16)171819class DataLoader:20"""Loads Bible source texts and metadata from JSON files."""2122def __init__(self, data_dir: Path | str) -> None:23"""Initialize the data loader.2425Args:26data_dir: Path to the data directory containing sources and metadata.27"""28self.data_dir = Path(data_dir)29self.sources_dir = self.data_dir / "sources"30self.metadata_dir = self.data_dir / "metadata"3132def _load_json(self, path: Path) -> dict[str, Any]:33"""Load a JSON file."""34if not path.exists():35return {}36with path.open("r", encoding="utf-8") as f:37return json.load(f)3839def load_greek_book(self, book: str) -> dict[str, str]:40"""Load Greek source text for a book.4142Returns:43Dictionary mapping verse references to Greek text.44"""45path = self.sources_dir / "greek" / f"{book}.json"46return self._load_json(path)4748def load_japanese_meiji(self, book: str) -> dict[str, str]:49"""Load Meiji translation for a book."""50path = self.sources_dir / "japanese" / "meiji" / f"{book}.json"51return self._load_json(path)5253def load_japanese_taisho(self, book: str) -> dict[str, str]:54"""Load Taisho translation for a book."""55path = self.sources_dir / "japanese" / "taisho" / f"{book}.json"56return self._load_json(path)5758def load_japanese_kougo(self, book: str) -> dict[str, str]:59"""Load Kougo-yaku translation for a book (1954-1955)."""60path = self.sources_dir / "japanese" / "kougo" / f"{book}.json"61return self._load_json(path)6263def load_english_kjv(self, book: str) -> dict[str, str]:64"""Load KJV translation for a book."""65path = self.sources_dir / "english" / "kjv" / f"{book}.json"66return self._load_json(path)6768def load_english_asv(self, book: str) -> dict[str, str]:69"""Load ASV translation for a book."""70path = self.sources_dir / "english" / "asv" / f"{book}.json"71return self._load_json(path)7273def load_hebrew_book(self, book: str) -> dict[str, str]:74"""Load Hebrew source text for a book (OT only).7576Returns:77Dictionary mapping verse references to Hebrew text.78"""79path = self.sources_dir / "hebrew" / f"{book}.json"80return self._load_json(path)8182def load_verse(self, reference: VerseReference) -> Verse:83"""Load a verse with all available source texts.8485Args:86reference: The verse reference to load.8788Returns:89Verse object with all available source texts populated.90"""91ref_key = f"{reference.chapter}:{reference.verse}"9293greek = self.load_greek_book(reference.book)94hebrew = self.load_hebrew_book(reference.book)95meiji = self.load_japanese_meiji(reference.book)96taisho = self.load_japanese_taisho(reference.book)97kougo = self.load_japanese_kougo(reference.book)98kjv = self.load_english_kjv(reference.book)99asv = self.load_english_asv(reference.book)100101greek_data = greek.get(ref_key, {})102greek_text = (103greek_data.get("text") if isinstance(greek_data, dict) else greek_data104)105greek_translit = (106greek_data.get("translit") if isinstance(greek_data, dict) else None107)108109hebrew_data = hebrew.get(ref_key, {})110hebrew_text = (111hebrew_data.get("text") if isinstance(hebrew_data, dict) else hebrew_data112)113if hebrew_text:114# MorphHB marks morpheme boundaries with "/" inside words; strip115# them so the prompt receives normal Hebrew text.116hebrew_text = hebrew_text.replace("/", "")117hebrew_translit = (118hebrew_data.get("translit") if isinstance(hebrew_data, dict) else None119)120121greek_words = greek_data.get("words") if isinstance(greek_data, dict) else None122hebrew_words = hebrew_data.get("words") if isinstance(hebrew_data, dict) else None123124return Verse(125reference=reference,126greek_text=greek_text or None,127greek_translit=greek_translit,128hebrew_text=hebrew_text or None,129hebrew_translit=hebrew_translit,130greek_words=greek_words,131hebrew_words=hebrew_words,132japanese_meiji=meiji.get(ref_key),133japanese_taisho=taisho.get(ref_key),134japanese_kougo=kougo.get(ref_key),135english_kjv=kjv.get(ref_key),136english_asv=asv.get(ref_key),137)138139def load_chapter_verses(self, book: str, chapter: int) -> list[Verse]:140"""Load all verses for a chapter.141142Args:143book: Book name.144chapter: Chapter number.145146Returns:147List of Verse objects for the chapter.148"""149greek = self.load_greek_book(book)150hebrew = self.load_hebrew_book(book)151meiji = self.load_japanese_meiji(book)152taisho = self.load_japanese_taisho(book)153kougo = self.load_japanese_kougo(book)154kjv = self.load_english_kjv(book)155asv = self.load_english_asv(book)156157# Find all verses in this chapter from any source158verse_nums: set[int] = set()159for source in [greek, hebrew, meiji, taisho, kougo, kjv, asv]:160for key in source:161parts = key.split(":")162if len(parts) == 2 and int(parts[0]) == chapter:163verse_nums.add(int(parts[1]))164165verses = []166for verse_num in sorted(verse_nums):167ref = VerseReference(book=book, chapter=chapter, verse=verse_num)168verses.append(self.load_verse(ref))169170return verses171172def load_book_metadata(self, book: str) -> BookMetadata | None:173"""Load metadata for a book."""174path = self.metadata_dir / book / "book_context.json"175data = self._load_json(path)176if not data:177return None178return BookMetadata(**data)179180def load_chapter_summary(self, book: str, chapter: int) -> ChapterSummary | None:181"""Load summary for a chapter."""182path = self.metadata_dir / book / "chapter_summaries.json"183data = self._load_json(path)184chapter_data = data.get(str(chapter))185if not chapter_data:186return None187return ChapterSummary(book=book, chapter=chapter, **chapter_data)188189def load_glossary(self) -> list[GlossaryTerm]:190"""Load the theological term glossary.191192Supports both v1 and v2 glossary formats, auto-converting v1 on load.193"""194path = self.metadata_dir / "glossary.json"195return load_glossary_any_version(path)196197def get_book_chapters(self, book: str) -> list[int]:198"""Get list of chapter numbers for a book.199200Determines chapters by scanning available source files.201"""202chapters: set[int] = set()203204# Check all source directories205for source_path in [206self.sources_dir / "greek" / f"{book}.json",207self.sources_dir / "hebrew" / f"{book}.json",208self.sources_dir / "japanese" / "meiji" / f"{book}.json",209self.sources_dir / "english" / "kjv" / f"{book}.json",210]:211data = self._load_json(source_path)212for key in data:213# str.split always yields at least one part.214try:215chapters.add(int(key.split(":")[0]))216except ValueError:217continue218219return sorted(chapters)220