ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English

最新の記事

Algolia における「a に x を含み、b に y を含む」部分一致検索の調査

Algolia における「a に x を含み、b に y を含む」部分一致検索の調査

この記事は、AIが作成し、一部を人が修正したものです。 はじめに フルテキスト検索エンジンの中でも、Typesense、MeiliSearch、Algolia は小規模なプロジェクト向けの選択肢として注目されています。しかし、「a に x を含み、b に y を含む」部分一致検索 が可能かどうかは、プロジェクトの要件に関わる重要なポイントです。本記事では、Algolia での部分一致検索の可否や、Elasticsearch との比較を行います。 Algolia での部分一致検索 Algolia では、全文検索 (query) を利用できますが、特定のフィールドごとに部分一致検索を行うには制限があります。 方法1:query を使った検索(部分一致可能だがフィールド指定不可) index.search('x y') 特徴: x や y を含むデータを全フィールドから検索。 どのフィールドでヒットしたかを制限できない 。 方法2:restrictSearchableAttributes を使う(単一フィールドの検索) index.search('x', { restrictSearchableAttributes: ['a'] }); index.search('y', { restrictSearchableAttributes: ['b'] }); 特徴: a に x を含むデータ、b に y を含むデータを個別に検索可能。 両方の条件を同時に適用する方法はない 。 Algolia の結論 ✅ 部分一致検索は可能だが、複数フィールドの AND 条件は難しい 。 ❌ 「a に x を含み、b に y を含む」検索は標準では不可 。 Elasticsearch での部分一致検索 Elasticsearch では、bool クエリを使うことで「a に x を含み、b に y を含む」部分一致検索が可能です。 ...

WordファイルをTEI XMLに変換する方法:TEIgarage APIの活用ガイ

WordファイルをTEI XMLに変換する方法:TEIgarage APIの活用ガイ

この記事は、AIが作成し、一部を人が修正したものです。 はじめに デジタル人文学の世界では、文書をTEI(Text Encoding Initiative)形式で保存することが一般的になっています。TEIは学術的なテキストを構造化するための標準規格です。今回は、Microsoft Wordで作成した文書をTEI XML形式に変換する方法を、Pythonを使って解説します。 TEIgarageとは? TEIgarageは、さまざまな形式の文書をTEI XMLに変換するためのオンラインサービスです。このサービスはAPIを提供しており、プログラムから直接利用することができます。今回はこのAPIをPythonから呼び出して、Wordファイルを変換してみましょう。 必要なもの Python 3.6以上 requestsライブラリ(APIリクエスト用) インターネット接続 変換したいWordファイル(.docx形式) 手順 1. 必要なライブラリをインストールする まず、必要なライブラリをインストールしましょう。コマンドプロンプトやターミナルで以下のコマンドを実行します。 pip install requests 2. Pythonスクリプトを作成する 次に、以下のPythonコードをword_to_tei.pyなどの名前で保存します。 import requests import os import zipfile from io import BytesIO def convert_docx_to_tei_xml(file_path, output_path): # OxGarageのエンドポイント input_document_type = "docx%3Aapplication%3Avnd.openxmlformats-officedocument.wordprocessingml.document" output_document_type = "TEI%3Atext%3Axml" TEIGARAGE_URL = f"https://teigarage.tei-c.org/ege-webservice/Conversions/{input_document_type}/{output_document_type}/" # .docx ファイルを開いてAPIに送信 with open(file_path, "rb") as file: files = {"file": file} response = requests.post(TEIGARAGE_URL, files=files) # 変換結果をファイルとして保存せずに展開 if response.status_code == 200: # zipファイルをメモリ上で展開 with zipfile.ZipFile(BytesIO(response.content)) as zip_ref: # tei.xmlファイルを保存 for member in zip_ref.namelist(): if member.endswith("tei.xml"): zip_ref.extract(member, os.path.dirname(output_path)) tei_xml_path = os.path.join(os.path.dirname(output_path), member) os.rename(tei_xml_path, output_path) print("TEI/XML 変換成功!tei.xml に保存されました。") break else: print("エラー: tei.xml ファイルが見つかりません。") else: print("エラー:", response.status_code, response.text) # メイン処理 if __name__ == "__main__": # 変換したいWordファイルのパスを指定 word_file = "documents/sample.docx" # ここを実際のファイルパスに変更してください # 出力ファイルのパスを指定 output_file = "output/sample_tei.xml" # 出力先を指定 try: # Wordファイルを変換 convert_docx_to_tei_xml(word_file, output_file) except Exception as e: print(f"エラーが発生しました: {e}") 3. スクリプトを実行する スクリプト内のword_file変数を、変換したいWordファイルの実際のパスに変更します。同様に、output_file変数も希望の出力先に変更してください。 ...

DrupalのSortableviewsモジュールを使って、コンテンツを並び替えて、その結果をフィールドに保存する

DrupalのSortableviewsモジュールを使って、コンテンツを並び替えて、その結果をフィールドに保存する

概要 DrupalのSortableviewsモジュールを使って、コンテンツを並び替えて、その結果をフィールドに保存する方法について紹介します。 https://www.drupal.org/project/sortableviews 以下のように説明されています。 This one is similar to Draggableview module except it can save the position value ( After drag and drop the question ) into custom content type field. これは DraggableViews モジュールと似ています が、ドラッグ&ドロップで並び替えた後の 位置情報をカスタムコンテンツタイプのフィールドに保存できる 点が異なります。 インストール 通常の方法でインストールできました。 コンテンツタイプの作成 ソート対象のコンテンツタイプを作成します。ここでは、teamというコンテンツタイプを対象にします。 そして並び順の重みを保存するためのweightフィールドを作成しました。 Viewsの作成 作成したViewsは以下です。 まず、フォーマットを「Sortable table」にします。この時、field to use for weightの項目で、重みを保存したいフィールドを選択します。 次に、フィールドで「Sortableviews: Drag and drop …」を追加します。これにより、以下のようにドラッグ&ドロップのためのアイコンが表示されます。 さらに、並び替え基準として、「weight(昇順)」に設定しておきます。 最後、ヘッダーの部分で、「Save Sortableviews changes」を追加します。これにより、並び替え後に、「変更を保存」ボタンが表示されます。 APIからの利用 今回の設定では、ソート結果はfield_weightに保存されるため、例えば以下のようにAPIから利用できます。 /jsonapi/node/team?sort=field_weight 昇順に並び替えた結果を取得できます。これにより、decoupledな構成でもソート結果を利用することができます。 ...

Next.js + CETEIcean + React TEI Routerを使ったビューア開発

Next.js + CETEIcean + React TEI Routerを使ったビューア開発

概要 Next.js、CETEIcean、React TEI Routerを組み合わせたTEI/XMLビューアの開発についての備忘録です。 背景 CETEIceanは、TEI/XML を HTML5 に変換する JavaScript ライブラリです。 https://github.com/TEIC/CETEIcean そして、React TEI Routerは、CETEIcean をベースに React コンポーネントで TEI/XML を構造化して表示できるライブラリです。以下のように説明されています。 https://github.com/pfefferniels/react-teirouter TEI for React using CETEIcean and routes これらを組み合わせることで、Next.js において TEI/XML をカスタマイズして表示できるビューア を作成しました。 リポジトリ 以下がサンプルリポジトリです。 https://github.com/nakamura196/next-ceteicean-router 実際に動作するデモも用意しています。 https://next-ceteicean-router.vercel.app/ 実装 Next.js のページコンポーネント (page.tsx) CETEIcean を利用して XML を変換し、カスタムコンポーネントで描画します。 import React from "react"; import Render from "@/components/tei"; export default function App() { const xmlContent = `<?xml version="1.0" encoding="UTF-8"?> <TEI xmlns="http://www.tei-c.org/ns/1.0"> <text> <body> <div type="original"> 私の名前は<persName corresp="#id1">田中太郎</persName>です。 </div> <div> <p style="color: green;">こんにちは</p> <p style="color: green;">こんばんは <seg style="color: blue;">xxx</seg> </p> </div> </body> </text> </TEI>`; return <Render xmlContent={xmlContent} />; } TEIレンダリングコンポーネント CETEIcean を使って XML を HTML5 に変換。 TEIRender + TEIRoute を使い、TEI 要素ごとにカスタムコンポーネントを適用。 import { TEIRender, TEIRoute } from "react-teirouter";を使用した上で、要素毎にコンポーネントを用意しています。 ...

Next.js for Drupal の BASE_PATH 問題と修正方法(patch-package活用)

Next.js for Drupal の BASE_PATH 問題と修正方法(patch-package活用)

概要 Next.js for Drupalのv2.0.0が2025/2/11にリリースされました。 https://next-drupal.org/ https://next-drupal.org/blog/next-drupal-2-0 早速試してみたところ、BASE_PATHの取り扱いについて対応が必要だったので、備忘録です。 環境変数 環境変数のサンプルは以下のようになっています。 # See https://next-drupal.org/docs/environment-variables # Required NEXT_PUBLIC_DRUPAL_BASE_URL=https://site.example.com NEXT_IMAGE_DOMAIN=site.example.com # Authentication DRUPAL_CLIENT_ID=Retrieve this from /admin/config/services/consumer DRUPAL_CLIENT_SECRET=Retrieve this from /admin/config/services/consumer # Required for On-demand Revalidation DRUPAL_REVALIDATE_SECRET=Retrieve this from /admin/config/services/next この時、NEXT_PUBLIC_DRUPAL_BASE_URLにhttps://site.example.com/xxxのようなベースパスを含めた形で指定すると、APIのリクエストはhttps://site.example.com/jsonapi/などに送られ、リソースを正しく取得できませんでした。 原因 エラーが発生しているgetResourceCollectionを確認したところ、問い合わせ先のURLを作成するbuildUrl関数において、new URL(path, this.baseUrl);が使用されていました。 ... buildUrl(path, searchParams) { const url = new URL(path, this.baseUrl); const search = ( // Handle DrupalJsonApiParams objects. searchParams && typeof searchParams === "object" && "getQueryObject" in searchParams ? searchParams.getQueryObject() : searchParams ); if (search) { url.search = stringify(search); } return url; } ... async buildEndpoint({ locale = "", path = "", searchParams } = {}) { const localeSegment = locale ? `/${locale}` : ""; if (path && !path.startsWith("/")) { path = `/${path}`; } return this.buildUrl( `${localeSegment}${this.apiPrefix}${path}`, searchParams ).toString(); } ... async getResourceCollection(type, options) { options = { withAuth: this.withAuth, deserialize: true, ...options }; const endpoint = await this.buildEndpoint({ locale: options?.locale !== options?.defaultLocale ? options.locale : void 0, resourceType: type, searchParams: options?.params }); this.debug(`Fetching resource collection of type ${type}.`); const response = await this.fetch(endpoint, { withAuth: options.withAuth, next: options.next, cache: options.cache }); await this.throwIfJsonErrors( response, "Error while fetching resource collection: " ); const json = await response.json(); return options.deserialize ? this.deserialize(json) : json; } ChatGPTに質問したところ、以下の回答が得られました。 ...

DrupalのSearch API Algoliaモジュールを試す

DrupalのSearch API Algoliaモジュールを試す

概要 DrupalのSearch API Algoliaモジュールを試す機会がありましたので、備忘録です。 https://www.drupal.org/project/search_api_algolia インストール Drupal 11では、以下でインストールできました。 composer require 'drupal/search_api_algolia:^3.1' 設定 モジュールのインストール後、サーバとインデックスの設定を行います。 Add server Algoliaの設定画面で確認できる設定情報に基づき、サーバを作成します。ここでは、Write API Keyを使用しました。 Add index インデックスの作成以降は、他のモジュールでの設定と同様です。以下は、Amazon OpenSearch Serviceを使用する例です。 設定後、インデクシングを行います。 結果 以下のように、Drupalへのコンテンツ登録や更新に応じて、Algoliaのインデックスも更新されました。 まとめ このような連携により、Algoliaを用いた高速および柔軟な検索を行うことが可能になりました。 Drupalの活用にあたり、参考になりましたら幸いです。

DrupalのJSON:APIを用いて、ユーザ名とパスワードでデータ登録を行う

DrupalのJSON:APIを用いて、ユーザ名とパスワードでデータ登録を行う

概要 過去に、DrupalのJSON:APIを用いて、Pythonによるデータ登録を行う記事を執筆しました。 以下は、Basic認証を用いた方法です。 また以下は、API Keyを用いた方法です。 これらに加えて、通常のログインによる登録を行うことができたので、備忘録です。 コード 以下の通りです。ログインやCSRFトークンを取得した上で、コンテンツを登録します。 import requests import json import os from dotenv import load_dotenv class ApiClient: def __init__(self): load_dotenv(override=True) # DrupalサイトのURL(例) self.DRUPAL_BASE_URL = os.getenv("DRUPAL_BASE_URL") # エンドポイント(JSON:API) # self.JSONAPI_ENDPOINT = f"{self.DRUPAL_BASE_URL}/jsonapi/node/article" # 認証情報(Basic認証) self.USERNAME = os.getenv("USERNAME") self.PASSWORD = os.getenv("PASSWORD") def login(self): # ログインリクエスト login_url = f"{self.DRUPAL_BASE_URL}/user/login?_format=json" login_response = requests.post( login_url, json={"name": self.USERNAME, "pass": self.PASSWORD}, headers={"Content-Type": "application/json"} ) if login_response.status_code == 200: self.session_cookies = login_response.cookies def get_csrf_token(self): # CSRFトークンを取得 csrf_token_response = requests.get( f"{self.DRUPAL_BASE_URL}/session/token", cookies=self.session_cookies # ここでログインセッションを渡す ) if csrf_token_response.status_code == 200: # return csrf_token_response.text # self.csrf_token = csrf_token_response.text self.headers = { "Content-Type": "application/vnd.api+json", "Accept": "application/vnd.api+json", "X-CSRF-Token": csrf_token_response.text, } else: # raise Exception(f"CSRFトークン取得失敗: {csrf_token_response.status_code} {csrf_token_response.text}") self.csrf_token = None def create_content(self, data: dict): # 記事作成リクエスト url = f"{self.DRUPAL_BASE_URL}/jsonapi/{data['data']['type'].replace('--', '/')}" response = requests.post( # self.JSONAPI_ENDPOINT, url, headers=self.headers, cookies=self.session_cookies, json=data ) if response.status_code == 201: print("コンテンツが作成されました!") else: print("エラー:", response.status_code, response.text) これにより、以下で、コンテンツを登録することができました。 ...

Next.jsで多言語対応の静的サイトを構築する

Next.jsで多言語対応の静的サイトを構築する

はじめに この記事は、GPT-4oによって生成された内容です。Next.jsを使用して多言語対応の静的サイトを構築する方法について説明します。特に、メイン言語にはURLプレフィックスを付けず、その他の言語にはプレフィックスを付ける設定に焦点を当てます。GitHub Pagesを使用してデプロイする設定も含まれています。 プロジェクトのセットアップ まず、Next.jsのプロジェクトを作成します。create-next-appを使用してプロジェクトを初期化します。 npx create-next-app@latest next-intl-ssg 必要なパッケージのインストール 多言語対応のために、next-intlをインストールします。 npm install next-intl プロジェクト構成 プロジェクトのディレクトリ構成は以下の通りです。 src/app/[locale]/about/page.tsx src/app/about/page.tsx src/lib/i18n.ts src/components/I18nProvider.tsx src/i18n/ja.json src/i18n/en.json 多言語対応の実装 next-intlを使用して、言語ごとのメッセージを管理します。src/lib/i18n.tsでメッセージを取得する関数を定義しています。 export async function getMessages(locale: string) { return (await import(`@/i18n/${locale}.json`)).default; } I18nProviderコンポーネントを使用して、各ページでメッセージを提供します。 import { ReactNode } from 'react'; import { NextIntlClientProvider } from 'next-intl'; export default function I18nProvider({ children, locale, messages }: { children: ReactNode; locale: string; messages: Record<string, Record<string, string>>; }) { return ( <NextIntlClientProvider locale={locale} messages={messages}> {children} </NextIntlClientProvider> ); } SSGの設定 generateStaticParams関数を使用して、静的ページを生成する際のパラメータを設定します。メイン言語(日本語)にはプレフィックスを付けず、その他の言語にはプレフィックスを付けます。 // src/app/[locale]/about/page.tsx export function generateStaticParams() { return locales.filter(locale => locale !== 'ja').map(locale => ({ locale })); } GitHub Pagesへのデプロイ GitHub Actionsを使用して、GitHub Pagesにデプロイします。.github/workflows/deploy.ymlでデプロイの設定を行います。 name: Deploy to GitHub Pages on: push: branches: [main] workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: "pages" cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ./out deploy: environment: github-pages runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 リンク GitHubリポジトリ: next-intl-ssg GitHub Pages: next-intl-ssg まとめ このブログでは、Next.jsを使用して多言語対応の静的サイトを構築し、メイン言語にはプレフィックスを付けず、その他の言語にはプレフィックスを付ける方法を紹介しました。next-intlを活用することで、簡単に多言語対応が可能になります。ぜひ試してみてください。 ...

大きな画像から部分画像の座標を取得する方法

大きな画像から部分画像の座標を取得する方法

概要 大きな画像の一部が切り出された複数の画像から、元の画像内での座標を取得する機会がありました。本記事では、そのための方法についての備忘録をまとめます。 OpenCV の SIFT (Scale-Invariant Feature Transform) を用いて、テンプレート画像と元の画像を特徴点マッチングし、アフィン変換を推定して座標を取得する方法を紹介します。 実装 必要なライブラリ pip install opencv-python numpy tqdm Pythonコード 以下のコードでは、指定した大きな画像 (image_path) に対して、テンプレート画像 (templates_dir 内の PNG 画像) を SIFT でマッチングし、元の画像内の座標を取得します。 import cv2 import numpy as np from glob import glob from tqdm import tqdm import os # 画像読み込み def load_image_gray(path): img = cv2.imread(path, cv2.IMREAD_GRAYSCALE) if img is None: print(f"画像が見つかりません: {path}") return img # 特徴点抽出 def extract_features(image, detector): return detector.detectAndCompute(image, None) # マッチング処理 def match_features(des1, des2, matcher, ratio_test=0.7, min_matches=4): matches = matcher.knnMatch(des1, des2, k=2) good_matches = [m for m, n in matches if m.distance < ratio_test * n.distance] return good_matches if len(good_matches) >= min_matches else None # アフィン変換推定 def estimate_affine_transform(kp1, kp2, good_matches): src_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) dst_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) M_affine, _ = cv2.estimateAffinePartial2D(src_pts, dst_pts, method=cv2.RANSAC, ransacReprojThreshold=5.0) return M_affine # 画像上にマッチング結果を描画 def draw_matched_rectangle(image, M_affine, templ_shape): h, w = templ_shape rect_pts = np.float32([[0, 0], [w, 0], [w, h], [0, h]]) # 長方形の四隅 transformed_pts = cv2.transform(np.array([rect_pts]), M_affine)[0] # 変換後の座標 cv2.polylines(image, [np.int32(transformed_pts)], isClosed=True, color=(0, 0, 255), thickness=2) return transformed_pts # メイン処理 def main(image_path, templates_dir, output_path): # 画像とテンプレート一覧の読み込み img = load_image_gray(image_path) templ_paths = glob(templates_dir) dst_img = cv2.imread(image_path) # SIFT特徴量検出器 & BFMatcher 設定 sift = cv2.SIFT_create() bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=False) kp1, des1 = extract_features(img, sift) # 特徴点が見つからなかった場合 if des1 is None: print("対象画像の特徴点が見つかりませんでした。") return for templ_path in tqdm(templ_paths): templ = load_image_gray(templ_path) if templ is None: continue kp2, des2 = extract_features(templ, sift) if des2 is None: continue good_matches = match_features(des1, des2, bf) if good_matches is None: print(f"特徴点のマッチングが不足: {templ_path}") continue # アフィン変換推定 M_affine = estimate_affine_transform(kp1, kp2, good_matches) if M_affine is None: print(f"アフィン変換推定に失敗: {templ_path}") continue # 矩形描画 best_dst = draw_matched_rectangle(dst_img, M_affine, templ.shape) # ファイル名を矩形の近くに表示 x, y, _, _ = cv2.boundingRect(best_dst) base_name = os.path.splitext(os.path.basename(templ_path))[0] cv2.putText(dst_img, base_name, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # 結果を保存 cv2.imwrite(output_path, dst_img) print(f"結果画像を保存しました: {output_path}") 実行 # 実行 if __name__ == "__main__": # パラメータ設定 IMAGE_PATH = "/xxx/default.jpg" TEMPLATES_DIR = "/xxx/*.png" OUTPUT_PATH = "/xxx/match_result.jpg" main(IMAGE_PATH, TEMPLATES_DIR, OUTPUT_PATH) まとめ 本記事では、SIFT を用いた特徴点マッチング によって、部分画像が元画像のどこに位置するかを推定し、アフィン変換 で位置を特定する方法を紹介しました。 ...

Mirador3のFirebase連携annotationsプラグインにおいて、メールアドレスによる登録を可能にしました。

Mirador3のFirebase連携annotationsプラグインにおいて、メールアドレスによる登録を可能にしました。

概要 Mirador3のFirebase連携annotationsプラグインを開発しています。 こちらについて、これまではGoogleアカウントによるログイン機能のみを提供していましたが、メールアドレスによるログイン機能を追加しました。 機能紹介 以下、ログインボタンを押した場合です。 メールアドレスによるログインの場合、アカウントの新規作成が可能です。 ログイン後、ユーザに関する情報を表示するようにしました。 アイコンをクリックすると、ログアウトボタンが表示されます。 まとめ IIIFを用いたアノテーションの作成と共有において、参考になりましたら幸いです。

vttファイルからTEI/XMLを作成する

vttファイルからTEI/XMLを作成する

概要 vttファイルからTEI/XMLファイルを作成する方法の備忘録です。 さらに、IIIFマニフェストから、vttファイルおよびTEI/XMLファイルにアクセスできるようにしてみます。結果、以下のように、TEI/XMLファイルがSeeAlsoに関連づけられ、また「Annotations」タブから、vttファイルの内容にアクセスできます。 https://clover-iiif-demo.vercel.app/?manifest=https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177_vtt.json 参考 以下の「The Ethiopian Language Archive」における取り組みを参考にしました。特に、TEI/XMLの構造化方法が特に参考になりました。 https://dev.jael.info/documentation/ 例 以下で作成したvttファイルを対象とします。 具体的には、以下の『県政ニュース 第1巻』(県立長野図書館)を使用します。 https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177 TEI/XMLの作成 作成したTEI/XMLファイルの例は以下です。 https://movie-tei-demo.vercel.app/data/sdcommons_npl-02FT0102974177/sdcommons_npl-02FT0102974177.xml 具体的には以下です。 <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?> <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> <teiCorpus xmlns="http://www.tei-c.org/ns/1.0"> <teiHeader> <fileDesc> <titleStmt> <title>県政ニュース 第1巻</title> </titleStmt> <publicationStmt> <distributor>中村覚</distributor> <availability> <licence target="http://creativecommons.org/licenses/by/4.0/">http://creativecommons.org/licenses/by/4.0/</licence> </availability> </publicationStmt> <notesStmt> <note>昭和30年に長野県が制作した記録映像。次の8タイトルを収録する。「地方選挙終る」、「地方選挙後初の県議会開かる」、「三十年度を賄う県のお台所」、「すすむ土木建設」、「明るく正しく健やかに」、「幕をとじた善光寺の御開帳」、「勇ましい水防訓練」、「お国じまん民謡大会」</note> </notesStmt> <sourceDesc> <biblStruct> <monogr> <title>県政ニュース 第1巻</title> <availability> <licence target="https://creativecommons.org/publicdomain/zero/1.0/">cc0</licence> </availability> <imprint> <publisher>信州デジタルコモンズ 県立長野図書館所蔵資料</publisher> </imprint> </monogr> <ref target="https://www.ro-da.jp/shinshu-dcommons/library/02FT0102974177">信州デジタルコモンズ 県立長野図書館所蔵資料</ref> </biblStruct> </sourceDesc> </fileDesc> </teiHeader> <TEI> <teiHeader> <fileDesc> <titleStmt> <title>県政ニュース 第1巻</title> </titleStmt> <publicationStmt> <p /> </publicationStmt> <notesStmt> <note /> </notesStmt> <sourceDesc> <p /> </sourceDesc> </fileDesc> <revisionDesc> <change when="2025-02-18"> 作成 </change> </revisionDesc> </teiHeader> <text> <body> <timeline unit="ms"> <when absolute="00:00:00.000" xml:id="t1" /> <when absolute="00:00:25.500" xml:id="t2" /> <when absolute="00:00:38.500" xml:id="t3" /> <when absolute="00:00:50.500" xml:id="t4" /> <when absolute="00:00:55.500" xml:id="t5" /> <when absolute="00:01:03.500" xml:id="t6" /> <when absolute="00:01:08.500" xml:id="t7" /> <when absolute="00:01:18.500" xml:id="t8" /> <when absolute="00:01:23.500" xml:id="t9" /> <when absolute="00:01:33.500" xml:id="t10" /> ... </timeline> <annotationBlock xml:id="ab1"> <u start="#t1" end="#t2">♪♪♪</u> </annotationBlock> <annotationBlock xml:id="ab2"> <u start="#t2" end="#t3">今年は選挙の当たり年。2月の総選挙に引き続いて、4月の県市町村と八木早の選挙で、長野県116万有権者の関心は非常な高まりようです。</u> </annotationBlock> <annotationBlock xml:id="ab3"> <u start="#t3" end="#t4">男女青年や婦人層はもちろんのこと、この老人も今年88を迎えたとはいえ、その慎重な投票ぶりが老いの表に一徹さを伺わせています。</u> </annotationBlock> <annotationBlock xml:id="ab4"> <u start="#t4" end="#t5">♪〜</u> </annotationBlock> <annotationBlock xml:id="ab5"> <u start="#t5" end="#t6">かくて県下における投票率、全国の上位を占める立派な成績を収めました。</u> </annotationBlock> <annotationBlock xml:id="ab6"> <u start="#t6" end="#t7">♪ ♪</u> </annotationBlock> <annotationBlock xml:id="ab7"> <u start="#t7" end="#t8">その日午後8時 きっかり、県下一斉に即日開票が行われました。</u> </annotationBlock> <annotationBlock xml:id="ab8"> <u start="#t8" end="#t9">その結果、長野県知事には、前知事の林寅氏が当選。</u> </annotationBlock> <annotationBlock xml:id="ab9"> <u start="#t9" end="#t10">またこれと同時に、県議会議員61名の当選も決定しました。</u> </annotationBlock> ... </body> </text> </TEI> </teiCorpus> IIIFマニフェストファイルの作成 上述したTEI/XMLファイルをseeAlsoに持つIIIFマニフェストファイルを作成しました。 ...

clover-iiifをNext.jsで使用する

clover-iiifをNext.jsで使用する

概要 clover-iiifをNext.jsで使用するサンプルリポジトリを作成したので、備忘録です。 https://clover-iiif-demo.vercel.app/ 背景 clover-iiifは以下のように説明されています。 https://github.com/samvera-labs/clover-iiif Extensible IIIF front-end toolkit and Manifest viewer. Accessible. Composable. Open Source. (日本語訳)拡張可能な IIIF フロントエンドツールキットとマニフェストビューア。 これをNext.jsで使用します。 データ 「校異源氏物語(国立国会図書館所蔵)」をサンプルデータとして使用します。 https://dl.ndl.go.jp/pid/3437686 リポジトリ 以下で公開しています。 https://github.com/nakamura196/clover-iiif-demo 以下を参考にしました。 https://samvera-labs.github.io/clover-iiif/docs/composing クライアントサイドでの実行にあたり、以下のような工夫が必要でした。 "use client"; import React, { Suspense } from "react"; import dynamic from "next/dynamic"; import { useSearchParams } from "next/navigation"; // Viewerコンポーネントを動的にインポート(SSRを無効化) const Viewer = dynamic( () => import("@samvera/clover-iiif/viewer"), { ssr: false } ); const WorkContent = () => { const searchParams = useSearchParams(); const manifestId = searchParams.get('manifest') || "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json"; return ( <article> <Viewer iiifContent={manifestId} /> </article> ); }; const Work = () => { return ( <Suspense fallback={<div>Loading...</div>}> <WorkContent /> </Suspense> ); }; export default Work; まとめ 不完全な点もあるかと思いますが、参考になりましたら幸いです。

Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードする

Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードする

概要 Mirador 3の mirador-annotations プラグインで、付与したアノテーションをダウンロードするための設定に関する備忘録です。 https://mirador-annotations.vercel.app/ 背景 以下の記事で、アノテーションをGoogleのFirestoreに登録する方法を紹介しました。 ここで登録したアノテーションをダウンロードするにあたり、mirador-annotationsプラグインでダウンロードオプションが提供されていたので、その方法について紹介します。 方法 以下がデモページのソースコードになりますが、exportLocalStorageAnnotationsというオプションをtrueにすることで、ダウンロードアイコンが表示されました。 import mirador from 'mirador/dist/es/src/index'; import annotationPlugins from '../../src'; import LocalStorageAdapter from '../../src/LocalStorageAdapter'; import AnnototAdapter from '../../src/AnnototAdapter'; const endpointUrl = 'http://127.0.0.1:3000/annotations'; const config = { annotation: { adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`), // adapter: (canvasId) => new AnnototAdapter(canvasId, endpointUrl), exportLocalStorageAnnotations: false, // display annotation JSON export button }, id: 'demo', window: { defaultSideBarPanel: 'annotations', sideBarOpenByDefault: true, }, windows: [{ loadedManifest: 'https://iiif.harvardartmuseums.org/manifests/object/299843', }], }; mirador.viewer(config, [...annotationPlugins]); ダウンロードによって得られるJSONファイルの例は以下です。canvas毎にダウンロードできます。 { "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1/annotations", "items": [ { "body": { "type": "TextualBody", "value": "<p>Cを変更</p>" }, "type": "Annotation", "motivation": "commenting", "target": { "selector": [ { "type": "FragmentSelector", "value": "xywh=5314,1983,195,206" }, { "type": "SvgSelector", "value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M5314.21383,2086.96256c0,-56.89385 43.74418,-103.01543 97.70536,-103.01543c53.96118,0 97.70536,46.12158 97.70536,103.01543c0,56.89385 -43.74418,103.01543 -97.70536,103.01543c-53.96118,0 -97.70536,-46.12158 -97.70536,-103.01543z\" data-paper-data=\"{"state":null}\" fill=\"none\" fill-rule=\"nonzero\" stroke=\"#00bfff\" stroke-width=\"3\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/></svg>" } ], "source": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "type": "Canvas", "partOf": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "type": "Manifest" } } }, "canvasId": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "created": { "seconds": 1739524276, "nanoseconds": 522000000 }, "id": "exlXeaswdsiuhcFiLWSl", "userName": "中村覚", "manifestId": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "modified": { "seconds": 1739526046, "nanoseconds": 354000000 } }, { "motivation": "commenting", "id": "rx2JMkwtwuQDgbtAIOoO", "created": { "seconds": 1739524259, "nanoseconds": 611000000 }, "manifestId": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "body": { "type": "TextualBody", "value": "<p>校異源氏物語</p>" }, "userName": "中村覚", "canvasId": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1", "target": { "selector": [ { "type": "FragmentSelector", "value": "xywh=478,307,748,3424" }, { "value": "<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M478.38073,3732.45418v-3424.85175h748.39353v3424.85175z\" data-paper-data=\"{"state":null}\" fill=\"none\" fill-rule=\"nonzero\" stroke=\"#00bfff\" stroke-width=\"3\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/></svg>", "type": "SvgSelector" } ], "source": { "partOf": { "id": "https://dl.ndl.go.jp/api/iiif/3437686/manifest.json", "type": "Manifest" }, "type": "Canvas", "id": "https://dl.ndl.go.jp/api/iiif/3437686/canvas/1" } }, "modified": { "seconds": 1739524259, "nanoseconds": 611000000 }, "type": "Annotation" } ], "type": "AnnotationPage" } まとめ Mirador 3の mirador-annotations プラグインの利用にあたり、参考になりましたら幸いです。 ...

Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発しました。

Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発しました。

概要 Mirador 3の mirador-annotations プラグイン向けに、Firestore用のアダプタを開発したので備忘録です。以下でお試しいただけます。 https://mirador-annotations.vercel.app/ 背景 Mirador 3の mirador-annotations プラグインは、デフォルトではローカルストレージにアノテーションが保存されます。 一方、以下の記事で紹介したように、アダプタを変更することで、ローカルストレージではない場所にアノテーションを保存することもできます。 そこで、今回はGoogleのFirestoreに保存するためのアダプタを開発しました。 使い方 ユーザごとにアノテーションを保存できる仕組みとしました。 そのため、まず以下のボタンから、ログインを行います。 ログイン後、自分が付与したアノテーションが表示されます。 アノテーションの登録方法に違いはありません。 ログアウトすると、アノテーションが非表示となります。 リポジトリ ソースコードは以下で公開しています。 https://github.com/nakamura196/mirador-annotations 特に、以下が今回開発したアダプタです。 https://github.com/nakamura196/mirador-annotations/blob/master/src/FirestoreAnnotationAdapter.js また、以下がログインを行うためのボタンです。 https://github.com/nakamura196/mirador-annotations/blob/master/src/GoogleAuthButton.js 開発される際には、.env.exampleを参考に、FirebaseのAPIキーなどを.envに記入します。 https://github.com/nakamura196/mirador-annotations/blob/master/.env.example まとめ 本アプリを使用することで、ユーザごとに、IIIF画像に対するアノテーションを簡単に管理できるようになると思います。 なお、冒頭でご紹介した本アプリのデモ環境に登録されたデータは任意のタイミングで削除する可能性があるのでご注意ください。

Algoliaでページネーションの上限を変更する

Algoliaでページネーションの上限を変更する

概要 Algolia では、検索結果のページネーションに制限 (paginationLimitedTo) が設定されており、デフォルトでは 1,000件 までの検索結果にしかアクセスできません。この設定を変更することで、ページネーションの最大件数を調整できます。 設定方法 ページネーションの上限 (paginationLimitedTo) を変更するには、以下の方法があります。 Algolia ダッシュボードから設定 Algolia にログイン 対象のインデックス を選択 Configuration(設定) → Pagination(ページネーション) を開く paginationLimitedTo の値を変更 その他 API による設定変更も可能なようです。 まとめ この設定を適切に活用することで、より柔軟な検索体験を提供できます。 参考になりましたら幸いです。

異体字リストを取得するためのAPIの試作

異体字リストを取得するためのAPIの試作

概要 以下のページで「史料編纂所データベース異体字同定一覧」が公開されています。 https://wwwap.hi.u-tokyo.ac.jp/ships/itaiji_list.jsp 今回は、上記のページで公開されているデータをJSON形式で取得するためのAPIを作成します。 開発したもの 以下のURLからアクセスいただけます。 https://hi-itaiji.vercel.app/ 同定一覧における「char(異体字)」をキーとして、「base」の漢字を値とするマッピングを返却します。 まとめ 異体字リストの応用にあたり、参考になりましたら幸いです。

Next 15(React 19 を使用)で、@react-three/fiberとdreiを使う

Next 15(React 19 を使用)で、@react-three/fiberとdreiを使う

概要 Next 15(React 19 を使用)で、@react-three/fiberを使う際、以下のように説明されています。 R3F v8 is not compatible with React 19 or Next 15, which uses React 19. Use the R3F v9 RC instead which can be installed with @react-three/fiber@rc. (日本語訳)R3F v8 は React 19 や Next 15(React 19 を使用)と互換性がありません。代わりに R3F v9 RC を使用してください。インストールするには @react-three/fiber@rc を使用してください。 一方、マウス操作を行うために以下を追加しましたが、@react-three/fiber@rcとは相性が悪いようでした。 https://www.npmjs.com/package/@react-three/drei この問題に対する対処法の備忘録です。 方法 本記事執筆時点(2025-02-06)の情報です。 まず、@react-three/fiber@rcではなく、@react-three/fiber@alphaをインストールする必要がありました。(@betaでもよいかもしれません。) そして、dreiについては、@react-three/drei@10.0.0-rc.1をインストールしました。結果、以下のような組み合わせでは、無事にインストールすることができました。 "@react-three/drei": "^10.0.0-rc.1", "@react-three/fiber": "^9.0.0-alpha.8", まとめ 考慮が不十分な点があるかもしれませんが、参考になりましたら幸いです。

Omeka Sにサイズが大きいファイルをアップロードする

Omeka Sにサイズが大きいファイルをアップロードする

概要 Omeka Sに比較的サイズが大きい(200MB超)ファイルをアップロードする機会がありましたので、備忘録です。 具体的には、3Dモデルを保存するために使用される3次元ファイル形式の.glbファイルをアップロードします。 課題 通常、比較的サイズが大きいファイルをGUIからアップロードを試みると、 以下のように「POST request exceeded maximum size」となることがあります。 これを対応方法の例を紹介します。 php.ini の設定変更 Omeka SはPHPの設定によってアップロードサイズの制限を受けるため、まずは php.ini の設定を確認・変更してください。 upload_max_filesize = 512M post_max_size = 512M max_execution_time = 300 変更後はWebサーバー(ApacheやNginx)を再起動してください。ただし、デメリットとして共有ホスティングでは変更できない場合などがあります。 直接サーバにアップロード Omeka SのGUIを経由せずに、サーバに直接ファイルをアップロードし、Omeka Sに認識させる方法もあります。 File Sideloadモジュール 以下で紹介したFile Sideloadモジュールが使用できます。 上記は一括登録の例ですが、以下のように「サイドロード:公式サイト以外からのファイル読込」オプションを使用して、サーバ上にアップロード済みのファイルを選択して登録することができます。 URL指定 サーバ上にアップロードしたファイルにURLでアクセスできる場合には、Omeka Sの標準機能を用いて登録することができます。 どの方法を選ぶべきか? 方法 メリット デメリット php.ini 設定変更 すぐに対応可能 共有ホスティングでは変更不可の場合あり File Sideloadモジュール GUI制限を回避 モジュールのインストールが必要 URL指定 一括登録が可能 URLの準備が必要 まとめ 他にも良い方法があるかもしれませんが、参考になりましたら幸いです。

IIIFマニフェストファイルからOCR結果を含むTEI_XMLファイルを作成するプログラム

IIIFマニフェストファイルからOCR結果を含むTEI_XMLファイルを作成するプログラム

概要 IIIFマニフェストファイルからOCR結果を含むTEI_XMLファイルを作成するプログラムを作成しました。このプログラムの使用方法について説明します。 仕組み IIIFマニフェストファイルのURLを指定して、NDL古典籍OCR-LiteによるOCR結果を含むTEI/XMLファイルを作成します。 https://github.com/ndl-lab/ndlkotenocr-lite 使い方 以下のノートブックにアクセスしてください。 https://colab.research.google.com/github/nakamura196/000_tools/blob/main/IIIFマニフェストファイルからTEI_XMLファイルを作成するプログラム.ipynb そして、一つ目の再生ボタンを押します。 完了したら、「実行」という部分のmanifest_urlとoutput_dirの値を更新して、セルを実行します。 output_dirに、OCR結果を含むTEI/XMLファイルが出力されます。 出力例 以下のように、ページおよび行ごとのOCR結果を含むファイルが作成されます。 <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?> <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> <TEI xmlns="http://www.tei-c.org/ns/1.0"> <teiHeader> <fileDesc> <titleStmt> <title>OCR結果: https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/0f11a3ed-18c2-7322-6340-19ed3f0d966e/manifest</title> </titleStmt> <publicationStmt> <publisher>NDL古典OCR</publisher> <date>2025-01-29</date> </publicationStmt> <sourceDesc> <bibl> <ptr target="https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/0f11a3ed-18c2-7322-6340-19ed3f0d966e/manifest"/> </bibl> </sourceDesc> </fileDesc> </teiHeader> <text> <body> <ab n="1" type="page" facs="https://iiif.dl.itc.u-tokyo.ac.jp/iiif/soto_ogai_202310/A05_4/002/A05_4_002_0001.tif/full/full/0/default.jpg"> <lb/> <seg type="本文" n="1" corresp="#zone-1">国外</seg> <lb/> <seg type="本文" n="3" corresp="#zone-3">空せみ二</seg> <lb/> <seg type="本文" n="4" corresp="#zone-4">ゆふかほ</seg> </ab> <ab n="2" type="page" facs="https://iiif.dl.itc.u-tokyo.ac.jp/iiif/soto_ogai_202310/A05_4/002/A05_4_002_0002.tif/full/full/0/default.jpg"> <lb/> <seg type="本文" n="1" corresp="#zone-1">あつたい</seg> <lb/> <seg type="本文" n="2" corresp="#zone-2">・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・</seg> <lb/> <seg type="本文" n="3" corresp="#zone-3">中川ノ中川宿にて之源氏十六才</seg> <lb/> <seg type="本文" n="4" corresp="#zone-4">住ぬ</seg> <lb/> <seg type="本文" n="5" corresp="#zone-5">ねられ給はぬまゝに。われはかく人に</seg> <lb/> <seg type="本文" n="6" corresp="#zone-6">にくまれてもならはぬを。こよひなん</seg> <lb/> <seg type="本文" n="7" corresp="#zone-7">はじめてうしと世を思ひ知ぬれば</seg> <lb/> <seg type="本文" n="8" corresp="#zone-8">はつかしうてながらふまじくこそ思ひ</seg> <lb/> <seg type="本文" n="9" corresp="#zone-9">なりぬれなどの給へば。なみたをさへ</seg> <lb/> <seg type="本文" n="10" corresp="#zone-10">こぼしてふしたり。いどらうたしと</seg> <lb/> <seg type="本文" n="11" corresp="#zone-11">おぼすてさぐりのほそくちいさき</seg> <lb/> <seg type="本文" n="12" corresp="#zone-12">ほどがみのいとながからざりしけ</seg> <lb/> まとめ 不完全な点もあるかと思いますが、参考になりましたら幸いです。 ...

校異源氏物語に対する類似テキスト検索アプリを作成しました。

校異源氏物語に対する類似テキスト検索アプリを作成しました。

概要 校異源氏物語に対する類似テキスト検索アプリを作成しました。以下のURLからお試しいただけます。 https://huggingface.co/spaces/nakamura196/genji_predict 本アプリの使用方法などについて紹介します。 データ 以下の校異源氏物語DBで公開されているテキストデータを使用します。 https://kouigenjimonogatari.github.io/ アプリの内容 仕組みは単純で、校異源氏物語の巻毎・ページ毎のテキストを用意しておき、入力された文字列との編集距離を算出し、類似度が高いテキスト(+巻とページ)を返却します。 ソースコードは以下です。 https://huggingface.co/spaces/nakamura196/genji_predict/tree/main 応用例 例えば、以下の「[源氏物語] [4](東京大学総合図書館所蔵)」では、1つのIIIFマニフェスト内に複数の巻が含まれており、何コマ目から何コマ目までが何巻に属するのか、素人には判断が難しい場合があります。 https://da.dl.itc.u-tokyo.ac.jp/portal/assets/b90bbddc-509d-7c12-0fb9-af409a90a487 そこで、上記に資料に対してコマ毎のOCRテキストを取得し、今回作成したアプリに問い合わせることで、ページ毎に推定される巻数が提示され、巻の変わり目を知る手助けを行うことができます。 OCR OCRにあたっては、NDL古典籍OCR-Liteを使用します。 https://github.com/ndl-lab/ndlkotenocr-lite OCR結果を修正して、以下のようなTEI/XMLを作成しました。 <?xml version="1.0" encoding="UTF-8"?> <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?> <?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> <TEI xmlns="http://www.tei-c.org/ns/1.0"> <teiHeader> <fileDesc> <titleStmt> <title>OCR結果: https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/b90bbddc-509d-7c12-0fb9-af409a90a487/manifest</title> </titleStmt> <publicationStmt> <publisher>NDL古典籍OCR-Lite</publisher> <date>2025-01-29</date> </publicationStmt> <sourceDesc> <bibl> <ptr target="https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/b90bbddc-509d-7c12-0fb9-af409a90a487/manifest"/> </bibl> </sourceDesc> </fileDesc> </teiHeader> <text> <body> <ab n="1" type="page" facs="https://iiif.dl.itc.u-tokyo.ac.jp/iiif/soto_ogai_202310/A05_4/004/A05_4_004_0001.tif/full/full/0/default.jpg"> <lb/> <seg type="本文" n="1" corresp="#zone-1-1">国外</seg> <lb/> <seg type="本文" n="3" corresp="#zone-1-3">紅葉のか</seg> <lb/> <seg type="本文" n="4" corresp="#zone-1-4">はなのえん</seg> <lb/> <seg type="本文" n="5" corresp="#zone-1-5">あふひ</seg> </ab> <ab n="2" type="page" facs="https://iiif.dl.itc.u-tokyo.ac.jp/iiif/soto_ogai_202310/A05_4/004/A05_4_004_0002.tif/full/full/0/default.jpg"> <lb/> <seg type="本文" n="1" corresp="#zone-2-1">OOO</seg> <lb/> <seg type="本文" n="2" corresp="#zone-2-2">□□□□□□□□</seg> <lb/> <seg type="本文" n="3" corresp="#zone-2-3">源氏十七才ノ十月より四年の十月迄有</seg> <lb/> <seg type="本文" n="4" corresp="#zone-2-4">/朱雀院の行幸ば。神無月の十日</seg> <lb/> <seg type="本文" n="5" corresp="#zone-2-5">あまりなり。よのつねならず。おもし</seg> <lb/> <seg type="本文" n="6" corresp="#zone-2-6">ろかるべきたびのこと成ければ。御</seg> <lb/> <seg type="本文" n="7" corresp="#zone-2-7">かた〴〵物見給はぬことを口おし</seg> <lb/> <seg type="本文" n="8" corresp="#zone-2-8">がり給。うへもなつぼの。み給はざらん</seg> <lb/> <seg type="本文" n="9" corresp="#zone-2-9">をあかずおぼさるれば。誠楽を御</seg> <lb/> <seg type="本文" n="10" corresp="#zone-2-10">前にてせさせ給ふ。源氏の中将は。</seg> <lb/> <seg type="本文" n="11" corresp="#zone-2-11">青海波をぞまひ給ける。かたてには。</seg> <lb/> <seg type="本文" n="12" corresp="#zone-2-12">火とのゝ頭中将がたちようい人にこ</seg> <lb/> <seg type="本文" n="13" corresp="#zone-2-13">となるを。立ならびては。花のかたはらの</seg> <lb/> <seg type="本文" n="14" corresp="#zone-2-14">みやまばなり。入がたの日かげさやか</seg> <lb/> <seg type="本文" n="15" corresp="#zone-2-15">にさしたるに。がくのこゑまさり。物の</seg> <lb/> <seg type="本文" n="16" corresp="#zone-2-16">おもしろきほどに。おなじまひのあ</seg> <lb/> <seg type="本文" n="17" corresp="#zone-2-17">しぶみおもゝち。よに見えぬさまなり。</seg> <lb/> <seg type="本文" n="18" corresp="#zone-2-18">詠などし給へるはこれや仏の御迦</seg> <lb/> <seg type="本文" n="19" corresp="#zone-2-19">一後順伽のこゑならんと聞ゆ。おもし</seg> </ab> <ab n="3" type="page" facs="https://iiif.dl.itc.u-tokyo.ac.jp/iiif/soto_ogai_202310/A05_4/004/A05_4_004_0003.tif/full/full/0/default.jpg"> <lb/> <seg type="本文" n="1" corresp="#zone-3-1">ろく哀なるに。みかと泪おとし給。</seg> <lb/> <seg type="本文" n="2" corresp="#zone-3-2">上達部みこたちもみななき給ぬ</seg> <lb/> <seg type="本文" n="3" corresp="#zone-3-3">詠はてゝ初うちなをし給へるにま</seg> <lb/> <seg type="本文" n="4" corresp="#zone-3-4">ちとりたるがくのにぎはゝしきに</seg> <lb/> <seg type="本文" n="5" corresp="#zone-3-5">かほの色あひまさりてつねよりも</seg> <lb/> <seg type="本文" n="6" corresp="#zone-3-6">ひかると見え給。春宮の女御。かく</seg> 推定 上記のXMLファイルを入力として、先に紹介したGradioアプリのAPIを利用します。 ...