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

最新の記事

Omeka Sテーマの多言語化

Omeka Sテーマの多言語化

はじめに Omeka Sのテーマ開発において、多言語化の実装方法に関する日本語の情報は限られています。本記事では、Omeka Sのカスタムテーマを多言語対応させる具体的な手順と、実装時の注意点について解説します。 目次 Omeka Sの翻訳システムの仕組み テーマの多言語化に必要なファイル ステップバイステップガイド よくある間違いと解決方法 実装例 トラブルシューティング 1. Omeka Sの翻訳システムの仕組み Omeka Sはgettext という標準的な翻訳システムを使用しています。このシステムでは: .poファイル:人間が読み書きできる翻訳ソースファイル .moファイル:コンパイル済みのバイナリファイル(実際に使用される) $translate()関数:PHPテンプレート内で翻訳を適用 2. テーマの多言語化に必要なファイル 必要なディレクトリ構造 your-theme/ ├── config/ │ └── theme.ini # 重要:has_translations = "true"を追加 ├── language/ │ ├── template.pot # 翻訳テンプレート(オプション) │ ├── ja.po # 日本語翻訳ソース │ └── ja.mo # 日本語翻訳バイナリ └── view/ └── (各種テンプレートファイル) 3. ステップバイステップガイド ステップ1:theme.iniの設定 config/theme.iniファイルの[info]セクションに以下の行を追加します: [info] name = "Your Theme Name" version = "1.0.0" author = "Your Name" description = "Theme description" omeka_version_constraint = "^4.1.0" has_translations = "true" # ← この行が重要! ⚠️ 重要: has_translations = "true"がないと、翻訳ファイルが読み込まれません。 ...

Cantaloupeでdelegate scriptを使ってAzure Storage上のファイルパスを動的に変換する方法

Cantaloupeでdelegate scriptを使ってAzure Storage上のファイルパスを動的に変換する方法

はじめに IIIFサーバーのCantaloupeでAzure Storageを使用している際、IIIF URLのidentifierと実際のAzure Storage上のファイルパスが異なる場合があります。本記事では、この問題をdelegate scriptを使って解決する方法を詳しく解説します。 課題 以下のようなファイル構造で画像を管理しているとします: Azure Storage Container: mycontainer ├── images/ │ ├── collection1/ │ │ ├── item001/ │ │ │ └── item001_001.jpg │ │ └── item002/ │ │ └── item002_001.jpg │ └── collection2/ │ └── ... しかし、IIIF URLでは以下のようにアクセスしたい: https://example.com/iiif/3/collection1/item001/item001_001.jpg/info.json この場合、IIIF URLのidentifier (collection1/item001/item001_001.jpg) と実際のAzure Storageのパス (images/collection1/item001/item001_001.jpg) が異なります。 AzureStorageSourceには、S3SourceのようなPATH_PREFIX設定が存在しないため、この問題を解決するためにはdelegate scriptを使用する必要があります。 解決方法 1. Docker Compose設定 services: cantaloupe: image: islandora/cantaloupe:main environment: CANTALOUPE_SOURCE_STATIC: AzureStorageSource CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_NAME: ${AZURE_STORAGE_ACCOUNT_NAME} CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_KEY: ${AZURE_STORAGE_ACCOUNT_KEY} CANTALOUPE_AZURESTORAGESOURCE_CONTAINER_NAME: ${AZURE_STORAGE_CONTAINER_NAME} CANTALOUPE_AZURESTORAGESOURCE_LOOKUP_STRATEGY: ScriptLookupStrategy # 重要 CANTALOUPE_DELEGATE_SCRIPT_ENABLED: "true" CANTALOUPE_DELEGATE_SCRIPT_PATHNAME: "/opt/cantaloupe/delegates.rb" volumes: - "./delegates.rb:/opt/cantaloupe/delegates.rb:ro" labels: - "traefik.enable=true" - "traefik.http.routers.cantaloupe.rule=Host(`example.com`)" - "traefik.http.routers.cantaloupe.entrypoints=websecure" - "traefik.http.routers.cantaloupe.tls=true" - "traefik.http.services.cantaloupe.loadbalancer.server.port=8182" restart: always 2. Delegate Script (delegates.rb) 開発・デバッグ版 最初はデバッグ出力を含む版で動作確認を行います: ...

Omeka Sの使い方を調べる

Omeka Sの使い方を調べる

概要 Omeka Sの使い方を調べる方法に関する備忘録です。 調べ方 公式マニュアル 公式マニュアルです。こちらが最も充実しており、最新の内容が反映されていると思います。 https://omeka.org/s/docs/user-manual/ Chat With Copilot 次に、自然言語で調べる方法として、「Chat With Copilot」を使用する方法です。 以下のリポジトリにアクセスして、 https://github.com/omeka/omeka-s-enduser 「Chat With Copilot」をクリックします。 以下のようなチャット画面において、質問を行うことができます。 DeepWiki Chat With Copilotと同様、自然言語で問い合わせることができる環境として、DeepWikiサイトを作成しました。 https://deepwiki.com/omeka/omeka-s-enduser 以下のように、日本語による問い合わせも可能です。 公式マニュアルの日本語版:最新版ではありません。 英語の公式マニュアルを機械翻訳によって日本語化したサイトを以下で公開しています。 https://nakamura196.github.io/omeka-s-enduser/ja/ 最新でなかったり、フォーマットが崩れているなど、不完全な点が多いですが、参考になりましたら幸いです。 Zennの本 こちらも不完全ですが、個人的にOmeka Sの使い方をまとめています。こちらも参考になりましたら幸いです。 https://zenn.dev/nakamura196/books/70ab821362fe2f まとめ LLMのおかげで、OSSリポジトリの使い方を調べる手間が大幅に減少していると思います。LLMの発展に感謝いたします。

RELAX NGとSchematronを組み合わせたTEI XMLスキーマの実装ガイド

RELAX NGとSchematronを組み合わせたTEI XMLスキーマの実装ガイド

! 人手で検証を行った後、AIが記事を執筆しました。 はじめに TEI(Text Encoding Initiative)XMLを編集する際、要素や属性の構造検証だけでなく、より複雑なビジネスルールの検証が必要になることがあります。本記事では、RELAX NG(RNG)とSchematronを組み合わせて、構造検証と内容検証の両方を実現する方法を、実際のプロジェクトで直面した課題を例に解説します。 解決したい課題 日本の古典文学テキストをTEI XMLで校訂する際、以下のような要求がありました: ID参照の動的検証 : corresp属性で参照するIDが、実際に文書内のwitness要素に存在することを検証したい Oxygen XML Editorでの補完機能 : 編集時にIDの候補を自動表示したい 複数ID参照のサポート : スペース区切りで複数のIDを指定可能にしたい 特定要素のみ参照を許可 : witness要素のIDのみを参照可能とし、person要素のIDが含まれる場合はエラーにしたい なぜRNG + Schematronなのか? RELAX NGの得意分野 要素・属性の構造定義 データ型の指定 基本的な内容モデルの定義 Schematronの得意分野 XPathベースの複雑な検証ルール 文書内の相互参照チェック カスタムエラーメッセージの提供 この2つを組み合わせることで、構造と内容の両面から厳密な検証が可能になります。 実装例 1. 基本的なRNGスキーマ構造 <?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="http://www.tei-c.org/ns/1.0"> <!-- Schematron名前空間宣言 --> <sch:ns prefix="tei" uri="http://www.tei-c.org/ns/1.0"/> <!-- ここにSchematronルールを埋め込む --> <start> <ref name="TEI"/> </start> <!-- RNGによる構造定義 --> </grammar> 2. ID定義とanyURI型の活用 Oxygen XML Editorで自動補完を実現するために、anyURI型を使用します: ...

Docker環境でDrupal 10にWDBモジュールをセットアップする手順

Docker環境でDrupal 10にWDBモジュールをセットアップする手順

概要 この記事では、Docker環境でDrupal 10を構築し、言語学データベース用のWDBモジュールをインストールする手順を解説します。 前提条件 Docker Desktop がインストールされていること Git がインストールされていること 手順 1. Docker環境の構築 まず、docker-compose.ymlファイルを作成します: services: mariadb: image: mariadb:latest restart: always volumes: - mariadb:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: drupal MYSQL_DATABASE: drupal MYSQL_USER: drupal MYSQL_PASSWORD: drupal drupal: image: drupal:10.2.7-php8.2-apache-bullseye volumes: - ./drupal/files:/opt/drupal/web/sites/default/files - ./drupal/modules:/opt/drupal/web/modules - ./drupal/themes:/opt/drupal/web/themes - ./drupal/private:/opt/drupal/private depends_on: - mariadb ports: - 8080:80 restart: always volumes: mariadb: {} 次に、必要なディレクトリを作成し、コンテナを起動します: ...

生成AIを用いてプロジェクトに特化したrngファイルを作成する

生成AIを用いてプロジェクトに特化したrngファイルを作成する

概要 TEI/XMLファイルを編集する際、検証に使用するrngファイルを変更することで、使用するタグや属性を限定することができます。これにより、作業者が使用するタグに混乱しない、作成されるTEI/XMLのばらつきが軽減する、といった利点が考えられます。 rngファイルを編集する方法として、以下の記事で紹介したように、Romaを使用する方法が一般的です。 この方法はトップダウン的に使用するタグや属性を限定していく方法ですが、今回は、すでに作成済みのTEI/XMLから、生成AIを用いて、ボトムアップ的にrngファイルを作成してみます。 対象データ 校異源氏物語テキストDBで公開されている以下のXMLファイルを対象とします。 https://kouigenjimonogatari.github.io/tei/01.xml このファイルでは、以下のtei_all.rngを使用しています。 http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng そのため、以下のように、挿入可能な多くのタグがサジェストされることがわかります。 生成AIによるrngファイルの作成 以下のようなプロンプトにより、対象とするXMLファイルのタグの使用状況などに応じて、rngファイルを作成します。 # XMLファイル用カスタムRNGスキーマ作成依頼 ## 目的 - 作業効率向上のため、使用する要素・属性を限定したRNGスキーマを作成 - 作業者がタグ選択に迷わず、一貫した構造で編集できる環境を構築 ## 提供するファイル - ファイル名: 01.xml ## 要望 1. **現在のXMLファイルを分析**し、実際に使用されている要素・属性を特定 2. **最小限かつ必要十分な要素セット**でRNGスキーマを作成 3. **入力補完・バリデーション**が効果的に働くよう設計 4. **コメント付き**で、各要素の用途を明記 ## 制約・方針 - 不要な要素は除外(例:○○、××は使用しない) - 必須属性を明確に定義 ## 期待する成果物 1. カスタムRNGファイル(.rng) 2. 簡潔な使用ガイド 結果、以下のrngファイルが作成されました。 <?xml version="1.0" encoding="UTF-8"?> <!-- カスタムRNGスキーマ: 校異源氏物語TEIファイル用 作成日: 2024年 【目的】 - 作業効率向上のため、実際に使用する要素・属性のみに限定 - 入力補完とバリデーションを効果的に機能させる - 作業者がタグ選択に迷わない明確な構造 --> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="http://www.tei-c.org/ns/1.0"> <start> <ref name="TEI"/> </start> <!-- ==================== ルート要素 ==================== --> <define name="TEI"> <element name="TEI"> <a:documentation>TEI文書のルート要素</a:documentation> <ref name="teiHeader"/> <ref name="facsimile"/> <ref name="text"/> </element> </define> <!-- ==================== ヘッダー部分(編集対象外) ==================== --> <define name="teiHeader"> <element name="teiHeader"> <a:documentation> メタデータ領域(編集作業では変更しない) - fileDesc: 書誌情報 - encodingDesc: エンコーディング情報 </a:documentation> <ref name="fileDesc"/> <ref name="encodingDesc"/> </element> </define> <!-- 書誌情報 --> <define name="fileDesc"> <element name="fileDesc"> <ref name="titleStmt"/> <ref name="publicationStmt"/> <ref name="sourceDesc"/> </element> </define> <!-- タイトル情報 --> <define name="titleStmt"> <element name="titleStmt"> <element name="title"> <text/> </element> <element name="author"> <text/> </element> <oneOrMore> <ref name="respStmt"/> </oneOrMore> </element> </define> <!-- 責任表示 --> <define name="respStmt"> <element name="respStmt"> <element name="resp"> <attribute name="when"> <a:documentation>作業日(YYYY-MM-DD形式)</a:documentation> <data type="date"/> </attribute> <text/> </element> <element name="name"> <text/> </element> </element> </define> <!-- 出版情報 --> <define name="publicationStmt"> <element name="publicationStmt"> <element name="distributor"> <text/> </element> <element name="date"> <attribute name="when"> <data type="date"/> </attribute> <text/> </element> <element name="availability"> <element name="p"> <element name="ref"> <attribute name="target"> <data type="anyURI"/> </attribute> <text/> </element> </element> </element> </element> </define> <!-- 原資料情報 --> <define name="sourceDesc"> <element name="sourceDesc"> <element name="bibl"> <element name="author"> <text/> </element> <element name="title"> <text/> </element> <element name="publisher"> <text/> </element> </element> </element> </define> <!-- エンコーディング情報 --> <define name="encodingDesc"> <element name="encodingDesc"> <element name="p"> <mixed> <optional> <element name="ref"> <attribute name="target"> <data type="anyURI"/> </attribute> <text/> </element> </optional> </mixed> </element> </element> </define> <!-- ==================== 画像参照部分 ==================== --> <define name="facsimile"> <element name="facsimile"> <a:documentation> 画像情報を管理する領域 - IIIF対応の画像URLとゾーン座標を定義 </a:documentation> <ref name="surfaceGrp"/> </element> </define> <!-- 画像グループ --> <define name="surfaceGrp"> <element name="surfaceGrp"> <attribute name="facs"> <a:documentation>IIIFマニフェストURL(必須)</a:documentation> <data type="anyURI"> <param name="pattern">https://.*\.json</param> </data> </attribute> <oneOrMore> <ref name="surface"/> </oneOrMore> </element> </define> <!-- 個別画像情報 --> <define name="surface"> <element name="surface"> <a:documentation>1つの画像面を表す</a:documentation> <ref name="graphic"/> <oneOrMore> <ref name="zone"/> </oneOrMore> </element> </define> <!-- 画像リンク --> <define name="graphic"> <element name="graphic"> <attribute name="n"> <a:documentation>IIIFキャンバスURL</a:documentation> <data type="anyURI"/> </attribute> <attribute name="url"> <a:documentation>画像の直接URL</a:documentation> <data type="anyURI"/> </attribute> <empty/> </element> </define> <!-- 画像上の領域定義 --> <define name="zone"> <element name="zone"> <a:documentation> 画像上の矩形領域を定義 - ページやコラムの範囲を指定 </a:documentation> <attribute name="xml:id"> <a:documentation>ゾーンID(zone_XXXX形式)</a:documentation> <data type="ID"> <param name="pattern">zone_\d{4}</param> </data> </attribute> <attribute name="lrx"> <a:documentation>右下X座標</a:documentation> <data type="nonNegativeInteger"/> </attribute> <attribute name="lry"> <a:documentation>右下Y座標</a:documentation> <data type="nonNegativeInteger"/> </attribute> <attribute name="ulx"> <a:documentation>左上X座標</a:documentation> <data type="nonNegativeInteger"/> </attribute> <attribute name="uly"> <a:documentation>左上Y座標</a:documentation> <data type="nonNegativeInteger"/> </attribute> <empty/> </element> </define> <!-- ==================== テキスト本文(主要編集領域) ==================== --> <define name="text"> <element name="text"> <a:documentation>テキスト本文のコンテナ</a:documentation> <ref name="body"/> </element> </define> <!-- 本文 --> <define name="body"> <element name="body"> <a:documentation>本文領域</a:documentation> <oneOrMore> <ref name="p"/> </oneOrMore> </element> </define> <!-- 段落 --> <define name="p"> <element name="p"> <a:documentation> 段落要素 - 通常は文書全体で1つのp要素を使用 </a:documentation> <ref name="textContent"/> </element> </define> <!-- ==================== テキストコンテンツモデル ==================== --> <define name="textContent"> <a:documentation> 本文内で使用可能な要素群 </a:documentation> <zeroOrMore> <choice> <text/> <ref name="lb"/> <ref name="pb"/> <ref name="seg"/> </choice> </zeroOrMore> </define> <!-- 改行 --> <define name="lb"> <element name="lb"> <a:documentation> 改行マーカー - 原本の改行位置を示す - 空要素として使用 </a:documentation> <empty/> </element> </define> <!-- ページ境界 --> <define name="pb"> <element name="pb"> <a:documentation> ページ境界マーカー - 新しいページの開始を示す - 必ず対応するzone要素を参照 </a:documentation> <attribute name="n"> <a:documentation>ページ番号(数値)</a:documentation> <data type="positiveInteger"/> </attribute> <attribute name="facs"> <a:documentation>対応するzoneへの参照(#zone_XXXX形式)</a:documentation> <data type="string"> <param name="pattern">#zone_\d{4}</param> </data> </attribute> <empty/> </element> </define> <!-- テキストセグメント(最重要要素) --> <define name="seg"> <element name="seg"> <a:documentation> テキストセグメント 【重要】主要な編集対象要素 - 1行または意味的なまとまりごとに分割 - 各セグメントは固有のIDを持つ外部リソースに対応 - corresp属性で外部データベースとリンク </a:documentation> <attribute name="corresp"> <a:documentation> 外部リソースへのリンク(必須) 形式: https://w3id.org/kouigenjimonogatari/api/items/XXXX-XX.json </a:documentation> <data type="anyURI"> <param name="pattern">https://w3id\.org/kouigenjimonogatari/api/items/\d{4}-\d{2}\.json</param> </data> </attribute> <text/> </element> </define> </grammar> XMLへの適用 以下のように、作成したrngファイルを適用します。 ...

Omeka S Docker の紹介:デジタルコレクションのための最新かつセキュアなソリューション

Omeka S Docker の紹介:デジタルコレクションのための最新かつセキュアなソリューション

! 本記事はAIが作成しました。 Omeka S Docker へようこそ!このプロジェクトは、大学、ギャラリー、図書館、アーカイブ、博物館向けの Web パブリケーションシステムである Omeka S の本番環境対応 Docker セットアップを提供します。 📦 GitHub リポジトリ : https://github.com/nakamura196/omeka-s-docker なぜ Omeka S Docker なのか? デジタルコレクションの管理は複雑である必要はありません。そのため、Omeka S のデプロイと管理を簡素化する Docker ベースのソリューションを作成しました。 主な機能 🚀 クイックセットアップ : シングルコマンドで数分以内に Omeka S を稼働 🔒 セキュリティファースト : 非 root コンテナとセキュアなデフォルト設定を含むセキュリティベストプラクティスで構築 📦 モジュール管理 : 人気の Omeka S モジュールの自動インストールとアップデート 🔄 簡単なアップグレード : データの永続性を保ちながらシームレスなバージョンアップグレード 🐳 本番環境対応 : 開発環境と本番環境の両方に最適化 🌐 Traefik 統合 : リバースプロキシと SSL 終端のビルトインサポート はじめに 前提条件 Docker と Docker Compose がインストールされていること コマンドラインの基本的な知識 (オプション)SSL 付き本番環境デプロイ用のドメイン名 セットアップオプションの理解 この Docker セットアップは2つのデプロイモードを提供します: ...

IIIF 3D Viewerを試作しました。

IIIF 3D Viewerを試作しました。

! 本記事はAIが作成しました。 はじめに デジタルヒューマニティーズの分野において、文化財や歴史的資料の3Dデジタル化が急速に進んでいます。しかし、3Dモデルを単に閲覧するだけでなく、学術的な分析や教育に活用するためには、適切なツールが必要です。本記事では、IIIF(International Image Interoperability Framework)規格に準拠した3Dモデルビューア「IIIF 3D Viewer」について紹介します。 IIIF 3D Viewerとは IIIF 3D Viewerは、IIIF Manifestフォーマットに基づいて3Dモデルを表示し、アノテーション機能を提供するウェブアプリケーションです。 主な特徴 標準規格への準拠 IIIF Presentation API 3.0に準拠 既存のIIIFエコシステムとの親和性 インタラクティブな3D表示 GLB/GLTFフォーマットのサポート マウスやタッチ操作による直感的な操作 WebGLを活用した高速レンダリング アノテーション機能 3Dモデル上の任意の点にアノテーションを追加 3DSelectorタイプによる空間座標の記録 学術的な注釈や解説の付与が可能 多言語対応 日本語・英語のインターフェース 国際的な研究プロジェクトでの利用を想定 静的サイト生成 Next.jsの静的エクスポート機能を活用 GitHub PagesやNetlifyなどで簡単にホスティング可能 技術的な実装 アーキテクチャ 本アプリケーションは、以下の技術スタックで構築されています: フロントエンドフレームワーク : Next.js 15(App Router) 3Dレンダリング : React Three Fiber + Three.js 国際化 : next-intl スタイリング : Tailwind CSS 型安全性 : TypeScript IIIF Manifestの構造 3Dモデルを含むIIIF Manifestの例: { "@context": "http://iiif.io/api/presentation/3/context.json", "id": "https://example.com/manifest.json", "type": "Manifest", "label": { "ja": ["石淵家地球儀"] }, "items": [ { "id": "https://example.com/canvas/1", "type": "Canvas", "items": [ { "id": "https://example.com/annotationpage/1", "type": "AnnotationPage", "items": [ { "id": "https://example.com/annotation/1", "type": "Annotation", "motivation": "painting", "body": { "id": "https://example.com/model.glb", "type": "Model", "format": "model/gltf-binary" }, "target": "https://example.com/canvas/1" } ] } ] } ] } アノテーションの実装 3D空間におけるアノテーションは、以下のような構造で表現されます: ...

「前近代日本-アジア関係資料デジタルアーカイブ」のビューアを試す

「前近代日本-アジア関係資料デジタルアーカイブ」のビューアを試す

概要 「前近代日本-アジア関係資料デジタルアーカイブ」が2025年7月25日に公開されました。 https://asia-da.lit.kyushu-u.ac.jp/ また、以下でビューアが公開されています。 https://github.com/localmedialabs/tei_comparative_viewer 本記事では、本ビューアを試した記録を共有します。 結果、以下のように、セルフホストすることができました。 https://tei-comparative-viewer.aws.ldas.jp/ 以下の「海東諸国紀」のXMLファイルを読み込んでいます。 https://asia-da.lit.kyushu-u.ac.jp/viewer/300 ローカルで起動する 以下に丁寧な説明がなされていますので、手順にしたがって起動させることができました。 https://github.com/localmedialabs/tei_comparative_viewer/blob/main/docs/SETUP.md サーバで起動する サーバで起動するにあたり、Dockerを用いて起動しました。 フォークしたリポジトリは以下です。 https://github.com/nakamura196/tei_comparative_viewer/tree/docker-traefik-setup 以下のようなファイルを用意しました。 FROM php:8.2-fpm # Install system dependencies RUN apt-get update && apt-get install -y \ git \ curl \ libpng-dev \ libonig-dev \ libxml2-dev \ zip \ unzip \ nodejs \ npm \ nginx \ supervisor # Clear cache RUN apt-get clean && rm -rf /var/lib/apt/lists/* # Install PHP extensions RUN docker-php-ext-install mbstring exif pcntl bcmath gd # Get latest Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Set working directory WORKDIR /var/www # Copy existing application directory contents COPY . /var/www # Install dependencies RUN composer install --no-dev --optimize-autoloader # Install and build frontend assets RUN npm install && npm run build # Remove default nginx site RUN rm -f /etc/nginx/sites-enabled/default # Copy nginx config COPY docker/nginx/app.conf /etc/nginx/sites-available/app.conf RUN ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/ # Copy PHP-FPM config COPY docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf # Copy supervisor config COPY docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf # Create necessary directories and set permissions RUN mkdir -p /var/log/supervisor \ && chown -R www-data:www-data /var/www \ && chmod -R 755 /var/www/storage \ && chmod -R 755 /var/www/bootstrap/cache # Generate key RUN php artisan key:generate # Optimize Laravel RUN php artisan config:cache && \ php artisan route:cache && \ php artisan view:cache # Expose port 80 EXPOSE 80 # Create PHP-FPM socket directory RUN mkdir -p /var/run/php # Start supervisord CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] services: app: build: context: . dockerfile: Dockerfile.prod.traefik container_name: tei_viewer_app restart: unless-stopped env_file: - .env.external volumes: - ./storage:/var/www/storage - ./public/assets:/var/www/public/assets networks: - traefik-network labels: - "traefik.enable=true" # HTTP router (redirects to HTTPS) - "traefik.http.routers.app-insecure.rule=Host(`xxx.yyy.zzz`)" - "traefik.http.routers.app-insecure.entrypoints=web" - "traefik.http.routers.app-insecure.middlewares=https-redirect" - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" # HTTPS router - "traefik.http.routers.app.rule=Host(`xxx.yyy.zzz`)" - "traefik.http.routers.app.entrypoints=websecure" - "traefik.http.routers.app.tls.certresolver=myresolver" - "traefik.http.services.app.loadbalancer.server.port=80" # Security headers - "traefik.http.middlewares.app-headers.headers.frameDeny=true" - "traefik.http.middlewares.app-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.app-headers.headers.browserXssFilter=true" - "traefik.http.middlewares.app-headers.headers.referrerPolicy=strict-origin-when-cross-origin" - "traefik.http.middlewares.app-headers.headers.stsSeconds=31536000" - "traefik.http.middlewares.app-headers.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.app-headers.headers.stsPreload=true" # Apply middlewares - "traefik.http.routers.app.middlewares=app-headers" networks: traefik-network: external: true # Application Environment APP_ENV=production APP_DEBUG=false APP_KEY= APP_URL=https://xxx.yyy.zzz # Domain Configuration (used in docker-compose labels) DOMAIN=xxx.yyy.zzz # Database DB_CONNECTION=sqlite # Session and Cache SESSION_DRIVER=file CACHE_DRIVER=file # Logging LOG_CHANNEL=stack # Mail (if needed) MAIL_MAILER=smtp # Other Laravel configurations as needed #!/bin/bash echo "=== TEI Comparative Viewer Setup with External Traefik ===" # .env.externalファイルが存在しない場合は作成 if [ ! -f .env.external ]; then echo "Creating .env.external file..." cp .env.external.example .env.external # アプリケーションキーを生成 echo "Generating application key..." docker run --rm \ -v $(pwd):/var/www \ -w /var/www \ php:8.2-cli \ php artisan key:generate --env=production --show | sed 's/base64://' > app_key.tmp # 生成したキーを.env.externalに設定 APP_KEY=$(cat app_key.tmp) sed -i.bak "s/APP_KEY=/APP_KEY=base64:$APP_KEY/" .env.external rm app_key.tmp .env.external.bak echo "Application key generated successfully!" fi # 設定の確認 echo "" echo "⚠️ IMPORTANT: Please edit .env.external and configure the following:" echo " 1. DOMAIN=your-domain.com (your actual domain)" echo " 2. APP_URL=https://your-domain.com (with HTTPS)" echo " 3. ASSET_URL=https://your-domain.com (for proper asset loading)" echo "" echo "Note: This setup assumes you have an external Traefik instance running" echo "with the 'traefik-network' already created." echo "" read -p "Press Enter to continue with the current settings..." # .envファイルをロード export $(cat .env.external | grep -v '^#' | xargs) # traefik-networkが存在するか確認 echo "Checking if traefik-network exists..." if ! docker network ls | grep -q traefik-network; then echo "❌ Error: traefik-network not found!" echo "Please ensure your external Traefik is running with traefik-network created." echo "" echo "If you need to create the network manually:" echo " docker network create traefik-network" exit 1 fi echo "✅ traefik-network found!" # 必要なディレクトリを作成 echo "Creating necessary directories..." mkdir -p storage/app/public mkdir -p storage/framework/{cache,sessions,views} mkdir -p storage/logs mkdir -p bootstrap/cache # まず.envファイルをコピー echo "Copying environment file..." cp .env.external .env # Dockerイメージをビルド(キー生成なしのDockerfileを使用) echo "Building Docker images..." if ! docker compose -f docker-compose-external.yml build; then echo "❌ Docker build failed. Trying without cache..." docker compose -f docker-compose-external.yml build --no-cache fi # コンテナを起動 echo "Starting containers..." docker compose -f docker-compose-external.yml up -d # 起動確認 echo "Waiting for services to be ready..." sleep 15 # アプリケーションキーが設定されていない場合は生成 echo "Checking and generating application key if needed..." if docker compose -f docker-compose-external.yml exec app php artisan key:generate --show | grep -q "base64:"; then echo "Generating new application key..." docker compose -f docker-compose-external.yml exec app php artisan key:generate --force fi # 権限を設定 echo "Setting permissions..." docker compose -f docker-compose-external.yml exec app chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache || echo "Permission setting completed" # 設定キャッシュをクリア echo "Clearing configuration cache..." docker compose -f docker-compose-external.yml exec app php artisan config:clear docker compose -f docker-compose-external.yml exec app php artisan config:cache docker compose -f docker-compose-external.yml exec app php artisan route:clear # アプリケーションの状態確認 echo "Checking application status..." if docker compose -f docker-compose-external.yml ps | grep -q "Up"; then echo "✅ Application container is running!" else echo "❌ Application container may have issues. Check logs:" echo " docker compose -f docker-compose-external.yml logs app" fi echo "" echo "✅ Setup complete!" echo "" echo "Application should be available at your configured domain (HTTPS)" echo "(assuming your external Traefik is properly configured and SSL certificates are set up)" echo "" echo "To stop the application, run:" echo " docker compose -f docker-compose-external.yml down" echo "" echo "To view logs, run:" echo " docker compose -f docker-compose-external.yml logs -f app" echo "" echo "To check Traefik routing (if dashboard is accessible):" echo " Check your Traefik dashboard for the new routes" echo "" echo "📝 Next steps:" echo " 1. Edit .env.external with your actual domain settings" echo " 2. Update docker-compose-external.yml Traefik labels with your domain" echo " 3. Ensure DNS is properly configured for your domain" まとめ 間違っている点もあるかもしれませんが、参考になりましたら幸いです。 ...

Next.js 15対応 多言語・ダークモード対応SSGテンプレート

Next.js 15対応 多言語・ダークモード対応SSGテンプレート

この記事は人間が実装を確認し、AIが記事を作成しました。 概要 このテンプレートは、Next.js 15を使用した静的サイト生成(SSG)に対応し、多言語対応とダークモードを標準装備したWebアプリケーション開発の出発点です。TypeScript、Tailwind CSS、next-intl、next-themesを組み合わせています。 https://nextjs-i18n-themes-ssg-template.vercel.app/ja/ 主な機能 1. 静的サイト生成(SSG) output: 'export'によるフルスタティックエクスポート 高速なページロードとSEO最適化 ホスティングコストの削減 2. 国際化対応(i18n) next-intlによる完全な多言語サポート 日本語・英語対応(簡単に言語追加可能) URLベースの言語切り替え(/ja/about、/en/about) 型安全な翻訳キー 3. ダークモード next-themesによるシステム連動ダークモード ユーザーの好みを自動検出 スムーズなテーマ切り替えアニメーション LocalStorageによる設定の永続化 4. 開発者体験の向上 TypeScriptによる型安全性 Tailwind CSSによる効率的なスタイリング ESLintによるコード品質管理 統一されたコンポーネント構造 技術スタック { "dependencies": { "next": "^15.4.4", "react": "^19.1.0", "next-intl": "^4.3.4", "next-themes": "^0.4.6", "tailwindcss": "^4.1.11", "@tailwindcss/typography": "^0.5.16" } } プロジェクト構造 src/ ├── app/ │ ├── [locale]/ │ │ ├── layout.tsx # ルートレイアウト │ │ ├── page.tsx # ホームページ │ │ ├── about/ # Aboutページ │ │ └── example/ # サンプルページ │ ├── icon.svg # ファビコン │ └── sitemap.ts # サイトマップ生成 ├── components/ │ ├── layout/ # レイアウトコンポーネント │ │ ├── Header.tsx │ │ ├── Footer.tsx │ │ ├── PageLayout.tsx │ │ ├── ToggleTheme.tsx │ │ └── ToggleLanguage.tsx │ └── page/ # ページ固有コンポーネント ├── i18n/ │ └── routing.ts # i18n設定 └── messages/ # 翻訳ファイル ├── en.json └── ja.json 特徴的な実装 1. sitemap.ts の静的エクスポート対応 export const dynamic = 'force-static'; export const revalidate = false; export default function sitemap(): MetadataRoute.Sitemap { // 実装 } 2. 統一されたページレイアウト <PageLayout breadcrumbItems={breadcrumbItems} title={t('title')} description={t('description')} > <YourContent /> </PageLayout> 3. 環境変数による設定 # .env.example NEXT_PUBLIC_SITE_URL=http://localhost:3000 NEXT_PUBLIC_BASE_PATH= 使い方 インストール git clone [repository-url] cd nextjs-i18n-themes-ssg-template npm install 開発 npm run dev ビルド npm run build カスタマイズポイント 言語追加 : src/i18n/routing.tsとmessages/ディレクトリ ページ追加 : src/app/[locale]/配下に新規ディレクトリ テーマカスタマイズ : tailwind.config.jsとグローバルCSS メタデータ : 各ページのgenerateMetadata関数 ベストプラクティス コンポーネント命名 : PascalCaseを使用 翻訳キー : ネストした構造で整理 型安全性 : TypeScriptの型を最大限活用 パフォーマンス : 静的生成を活用したキャッシュ戦略 まとめ 国際化対応とダークモード機能を標準装備し、SEOに最適化された静的サイトを素早く構築できるよう目指しています。開発者の生産性を向上させながら、エンドユーザーに優れた体験を提供していきたいと思います。 ...

Next.js 15 で output: 'export' 使用時の sitemap.ts 実装方法

Next.js 15 で output: 'export' 使用時の sitemap.ts 実装方法

この記事は人間が実装を確認したのち、AIが記事を執筆しました。 背景 Next.js 15で静的サイト生成(output: 'export')を使用する際、sitemap.tsの実装でエラーが発生する場合があります。 Error: export const dynamic = "force-static"/export const revalidate not configured on route "/sitemap.xml" with "output: export". 解決方法 この問題は、sitemap.tsに以下の2つのエクスポートを追加することで解決できます: // src/app/sitemap.ts import { MetadataRoute } from 'next'; export const dynamic = 'force-static'; export const revalidate = false; export default function sitemap(): MetadataRoute.Sitemap { // sitemap生成ロジック } 実装例 import { MetadataRoute } from 'next'; import { routing } from '@/i18n/routing'; export const dynamic = 'force-static'; export const revalidate = false; export default function sitemap(): MetadataRoute.Sitemap { const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'; const staticPages = [ '', // Home page '/about', '/example', ]; const sitemapEntries: MetadataRoute.Sitemap = routing.locales.flatMap((locale) => staticPages.map((page) => ({ url: `${baseUrl}/${locale}${page}`, lastModified: new Date(), changeFrequency: page === '' ? 'daily' : 'weekly' as const, priority: page === '' ? 1 : 0.8, })) ); return sitemapEntries; } 動作確認 この実装により、npm run build実行時に/out/sitemap.xmlが正常に生成されます。 注意点 dynamic = 'force-static'のみでは不十分で、revalidate = falseも必要です 環境変数やインポートしたモジュールの使用も可能です ビルド時に静的に解決される値であれば、動的な値も使用できます 代替案 もし上記の方法で解決しない場合は、以下の代替案があります: ...

Next.js × Search UI × Fuse.js 検索アプリケーション

Next.js × Search UI × Fuse.js 検索アプリケーション

概要 Next.js、Elastic Search UI、Fuse.jsを組み合わせた検索アプリケーションの技術構成と実装について説明します。 作成したサイトは以下です。 https://nsf-psi.vercel.app/ja/ GitHubリポジトリは以下です。 https://github.com/nakamura196/nsf サンプルデータとして、「東京帝國大學本部構内及農學部建物鳥瞰圖(東京大学農学生命科学研究科・農学部)」を使用します。 https://da.dl.itc.u-tokyo.ac.jp/portal/assets/187cc82d-11e6-9912-9dd4-b4cca9b10970 以下はAIが作成しました。 アプリケーション概要 このアプリケーションは、東京大学の建物画像データを対象とした検索システムです。IIIF(International Image Interoperability Framework)プロトコルに対応した建物画像を検索し、地理情報(緯度・経度)やメタデータを表示します。 主な特徴 多言語対応 next-intlによる日本語・英語の多言語対応機能を実装しています。 検索機能 簡易検索 : キーワードによる直感的な検索 詳細検索 : 複数条件を組み合わせた精密な検索(AND/OR条件) ファセット検索 : subject(学部)などカテゴリー別の絞り込み機能 ソート機能 : スコア、タイトル、属性値での並び替え 曖昧検索 : Fuse.jsによる入力ミスに寛容な検索(閾値0.3) UI/UX Tailwind CSSによる洗練されたデザイン ダークモード対応 レスポンシブデザインでモバイルフレンドリー React IconsによるアイコンUI カスタム検索コネクタ Elastic Search UIとFuse.jsを組み合わせたカスタムコネクタを実装し、フロントエンドのみで全文検索機能を実現しています。 地理情報対応 各建物データには緯度・経度情報が含まれています。 技術スタック フロントエンド Next.js 15 (App Router) React 19 TypeScript Tailwind CSS 4.0 検索システム Elastic Search UI(検索インターフェース) Fuse.js(全文検索エンジン) カスタムAPIConnector(独自実装) 国際化 next-intl その他 ...

IIIF認証API 2.0の動作確認

IIIF認証API 2.0の動作確認

概要 以下のIIIF認証API 2.0の動作確認を行う機会がありましたので、備忘録です。 https://iiif.io/api/auth/2.0/ 以下のようなデモサイトを作成しました。 https://iiif-auth-nextjs.vercel.app/ja リポジトリは以下です。 https://github.com/nakamura196/iiif-auth-nextjs 以下、AIによる説明です。なお、Miradorではうまく動作させることができなかったため、今後の課題です。 概要 本記事では、IIIF Authentication API 2.0 の認証フローを、実際のHTTPリクエスト/レスポンスのレベルで詳細に解説します。各ステップでどのようなリクエストが送信され、どのようなレスポンスが返されるのかを追跡していきます。 アーキテクチャ概要 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Client │────▶│ IIIF Server │────▶│Auth Service │ │ (Browser) │◀────│ │◀────│ │ └─────────────┘ └─────────────┘ └─────────────┘ 認証フローの詳細 Step 1: 初回の画像情報リクエスト(未認証) リクエスト: GET /api/iiif/image/sample/info.json HTTP/1.1 Host: localhost:3001 Accept: application/json 処理フロー(サーバー側): // app/api/iiif/image/[id]/info.json/route.ts export async function GET(request: NextRequest) { // 1. Authorizationヘッダーを確認 const authHeader = request.headers.get('authorization'); let token = authHeader?.replace('Bearer ', ''); // 2. クエリパラメータもチェック(フォールバック) if (!token) { token = request.nextUrl.searchParams.get('token') || ''; } // 3. トークンの検証 const isValid = token ? await verifyToken(token) : null; // 4. 未認証の場合は401を返す if (!isValid) { return NextResponse.json({ error: 'Authentication required', service: [{ "@context": "http://iiif.io/api/auth/2/context.json", "id": `${request.nextUrl.origin}/api/iiif/probe`, "type": "AuthProbeService2" }] }, { status: 401 }); } } レスポンス: ...

Recogitoを用いたテキストアノテーションを試す

Recogitoを用いたテキストアノテーションを試す

概要 Recogitoを用いたテキストアノテーションを試す機会がありましたので、備忘録です。 Recogitoは以下です。 https://recogito.pelagios.org/ 以下のように説明されています。 Semantic Annotation without the pointy brackets. Recogito is an annotation tool for texts and images - not just for Digital Humanities scholars. (機械翻訳)タグを使わないセマンティックアノテーション。デジタル人文学の研究者だけでなく、誰でも使えるテキストと画像のアノテーションツール サンプルデータ 国立国会図書館が公開する以下を例とします。 https://dl.ndl.go.jp/pid/2585164/1/1 使い方 Recogitoにアクセスし、画面右上の「ログイン」ボタンからログインします。 ログイン後、画面左部の「New」ボタンを押し、「From IIIF manifest」を選択します。 今回、サンプルデータとして使用する以下のマニフェストファイルを入力します。 https://dl.ndl.go.jp/api/iiif/2585164/manifest.json 以下のように、編集画面に遷移します。 その後、矩形を作成し、「Transcribe…」の箇所にテキストを入力します。 ダウンロード 画面上部のダウンロードアイコンから、各種フォーマットでエクスポートすることができます。 JSON-LDフォーマットでダウンロードした結果は以下です。Open Annotationに形式でエクスポートされました。 [ { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "https://recogito.pelagios.org/annotation/82be9a93-332b-4731-a9a4-5df8359eb197", "type": "Annotation", "generator": { "id": "https://recogito.pelagios.org/", "type": "Software", "name": "Recogito", "homepage": "https://recogito.pelagios.org/" }, "generated": "2025-07-23T06:23:59+00:00", "body": [ { "type": "TextualBody", "value": "御座候処貴地御揃奉仕請覚重候時御座候", "creator": "https://recogito.pelagios.org/satoru196", "modified": "2025-07-23T06:15:01+00:00", "purpose": "transcribing" } ], "target": { "source": "https://dl.ndl.go.jp/api/iiif/2585164/R0000005", "type": "Image", "label": "5", "selector": [ { "type": "FragmentSelector", "conformsTo": "http://www.w3.org/TR/media-frags/", "value": "xywh=pixel:4103,883,341,2385" } ] } }, { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "https://recogito.pelagios.org/annotation/caaa671f-79da-4a19-bc93-42a5502b4efa", "type": "Annotation", "generator": { "id": "https://recogito.pelagios.org/", "type": "Software", "name": "Recogito", "homepage": "https://recogito.pelagios.org/" }, "generated": "2025-07-23T06:23:59+00:00", "body": [ { "type": "TextualBody", "value": "一筆啓上仕候寒湿不順之気儘ニ", "creator": "https://recogito.pelagios.org/satoru196", "modified": "2025-07-23T06:12:45+00:00", "purpose": "transcribing" } ], "target": { "source": "https://dl.ndl.go.jp/api/iiif/2585164/R0000005", "type": "Image", "label": "5", "selector": [ { "type": "FragmentSelector", "conformsTo": "http://www.w3.org/TR/media-frags/", "value": "xywh=pixel:4319,901,360,2377" } ] } } ] まとめ Recogitoを用いたテキストアノテーションにあたり、参考になりましたら幸いです。 ...

GitHub File History Analyzerの紹介:ファイル編集履歴をAIで分析するツール

GitHub File History Analyzerの紹介:ファイル編集履歴をAIで分析するツール

本記事はAIが作成しました。 はじめに GitHubリポジトリで管理されているファイルの編集履歴を分析したいと思ったことはありませんか?特に長期間にわたって更新されているファイルの変更パターンや、プロジェクトの進化の過程を理解したい場合があります。 GitHub File History Analyzerは、このようなニーズに応えるために開発したコマンドラインツールです。 ツールの概要 このツールは以下の機能を提供します: GitHubのAPIを使用して特定ファイルのコミット履歴を取得 変更内容の統計的な分析(追加・削除行数、変更タイプの分類など) OpenRouter経由でAI(Gemini 2.5 Proなど)による編集パターンの分析 分析結果のMarkdown/JSON形式での出力 開発の背景 デジタルアーカイブプロジェクトで、XMLファイルの長期的な編集作業を追跡する必要がありました。単純なgit logでは得られない、より深い洞察(編集の傾向、作業の質、進捗状況など)を得たいという要求から、このツールの開発に至りました。 技術的な実装 使用技術 言語 : Python 3.8+ 主要ライブラリ : PyGithub(GitHub API wrapper) requests(HTTP通信) python-dotenv(環境変数管理) アーキテクチャ ツールは主に2つのコンポーネントで構成されています: GitHubFileHistoryAnalyzer : GitHub APIを使用してファイル履歴を取得・分析 OpenRouterClient : AI分析のためのクライアント # 基本的な使用例 analyzer = GitHubFileHistoryAnalyzer(github_token) commits = analyzer.get_file_history("owner/repo", "path/to/file.xml") analysis = analyzer.analyze_patches(commits) prompt = analyzer.generate_ai_prompt(commits, analysis) 実際の使用例 基本的なコマンド # ファイル履歴の取得と表示 python main.py --repo owner/repo --file path/to/file.py # AI分析の実行 python main.py --repo owner/repo --file path/to/file.py --analyze # 結果をMarkdown形式で保存 python main.py --analyze --ai-output analysis.md 分析結果の例 ツールは以下のような情報を提供します: ...

Transkuribusを試す

Transkuribusを試す

概要 Transkuribusを用いたテキストアノテーションを試す機会がありましたので、備忘録です。 Transkuribusは以下です。 https://www.transkribus.org/ 以下のように説明されています。 Transkribus enables you to automatically recognise text easily, edit seamlessly, collaborate effortlessly, and even train your custom AI for digitizing and interpreting historical documents of any form. (機械翻訳)あらゆる形式の歴史的文書をデジタル化・解釈するために、テキストの自動認識、シームレスな編集、効率的なコラボレーション、さらにカスタムAIのトレーニングまでを可能にするツール 参考 Transkuribusの日本語による説明として、以下が大変参考になりました。 https://connectivity.aa-ken.jp/ja/newsletter/588/index.html 一方、上記のページでご紹介いただいているデスクトップ版である「Transkribus eXpert」は、deprecatedになっていました。 https://help.transkribus.org/downloading-and-installing-transkribus-expert-deprecated Please note that Transkribus eXpert (desktop software) is no longer being updated, and all new features will be exclusively available on the Transkribus web app. サンプルデータ Recogitoについても、以下の使い方の記事を作成しました。 ...

grlc (git repository linked data API constructor)を試す

grlc (git repository linked data API constructor)を試す

概要 grlcのGitHubリポジトリは以下です。 https://github.com/CLARIAH/grlc 以下のように説明されています。 grlc, the git repository linked data API constructor, automatically builds Web APIs using shared SPARQL queries. (機械翻訳)grlc(git repository linked data API constructor)は、共有されたSPARQLクエリを使用して自動的にWeb APIを構築するツールです。 このツールを試してみましたので、備忘録です。 ジャパンサーチのSPARQL Endpointを対象に作成したAPIエンドポイントは以下です。 https://grlc.io/api-git/nakamura196/grlc-jps 背景 Odeuropaを調査する過程で、以下のページで本ツールについて言及されていることを見つけました。 https://odeuropa.eu/nosebooks/ 使い方 以下が今回のAPI用に作成したGitHubリポジトリです。 https://github.com/nakamura196/grlc-jps 例えば、以下はタイプの一覧を取得するAPI用のSPARQLクエリです。 #+ endpoint: https://jpsearch.go.jp/rdf/sparql/ #+ summary: 利用可能な文化財タイプ一覧 #+ description: Japan Searchで利用可能な文化財タイプの一覧を取得します #+ tags: #+ - タイプ一覧 #+ - メタデータ PREFIX jps: <https://jpsearch.go.jp/term/property#> SELECT ?type (COUNT(?cho) as ?count) WHERE { ?cho a ?type ; jps:sourceInfo ?source . } GROUP BY ?type ORDER BY DESC(?count) デコレータ構文を使用することで、swagger-uiに表示・設定する値を指定できるようでした。 ...

Odeuropaに関連するツールを試す

Odeuropaに関連するツールを試す

概要 Odeuropaに関連するツールを試す機会がありましたので、備忘録です。 Odeuropaとは 以下のページに説明があります。 https://odeuropa.eu/ 以下、機械翻訳の結果です。 Odeuropa(オドゥーロパ)は、ヨーロッパの「匂いの文化遺産」を研究するEU資金による革新的なプロジェクトです。 プロジェクトの目的: 1600年から1920年までのヨーロッパの歴史において、匂いが文化にどのような役割を果たしてきたかを調査・記録することです。最新のAI技術を使って、約4万3千点の画像と16万7千点の歴史的テキスト(英語、イタリア語、フランス語、オランダ語、ドイツ語、スロベニア語)から匂いに関する情報を抽出しています。 主な成果物: 匂い探索エンジン - 300年以上のヨーロッパの匂いの歴史を検索できるユニークなウェブサイト 匂いの歴史・遺産百科事典 - 専門家が執筆した匂いに関する文化的現象のオンライン参考書 嗅覚ストーリーテリング・ツールキット - 博物館や文化遺産機関が匂いを展示に活用するための実践ガイド 遺産匂いライブラリー - 歴史的に重要な匂いを調香師と協力して再現し、保存するコレクション このプロジェクトは、従来の視覚や聴覚中心の文化遺産の理解に、「嗅覚」という新しい次元を加えることで、より豊かで多感覚的な歴史体験を可能にしています。 ツール 以下のページで、関連する幾つかのツールが紹介されています。 https://odeuropa.eu/nosebooks/ Live Image Processing Demo 国立国会図書館の「近代日本人の肖像」で公開されている以下の画像を利用しました。 https://www.ndl.go.jp/portrait/datas/224 以下にアクセスし、画像のURLを指定します。 https://huggingface.co/spaces/mathiaszinnen/odeuropa-demo https://www.ndl.go.jp/portrait/img/portrait/0224_6.jpg 「Confidence Threshold」を0.2に設定した結果は以下です。手に持っているタバコを認識できているようでした。 Smells Extraction テキストから匂いを抽出するツールのようです。 https://smell-extractor.tools.eurecom.fr/ 匂いに関する記述を含む英語のサンプルテキストをAIに作成してもらいました。 As I walked past the bakery, the warm aroma of freshly baked bread and cinnamon rolls wafted through the air, making my mouth water instantly. Later that afternoon, when I stepped outside after the summer storm, the petrichor filled my nostrils - that distinctive earthy scent of rain on dry soil mixing with the sweet fragrance of wet grass. It reminded me of my visit to the old library last week, where the musty smell of aged paper and leather-bound books had greeted me as I entered, accompanied by hints of vanilla and almond from the decomposing lignin in the yellowing pages. This morning started differently though. The rich, nutty aroma of freshly ground coffee beans permeated the kitchen, its bitter-sweet scent promising the perfect start to my day. It was such a contrast to yesterday evening when I had wandered through the garden, where the heady perfume of jasmine blossoms hung heavy in the air, intermingling with the sharp, green smell of freshly cut grass and the subtle sweetness of roses. Nothing could have prepared me for today's trip to the seafood market, however, where the pungent odor of fish and brine assaulted my senses as I navigated through the crowded stalls, the salty tang of the ocean mixing with the metallic scent of ice and seafood. これを登録した結果が以下です。匂いに関する「Location」「Quality」「Smell Word」などが検出されていました。 ...

「れきちず x Next.js」にルートの登録機能を追加しました。

「れきちず x Next.js」にルートの登録機能を追加しました。

概要 「れきちず x Next.js」はれきちずとNext.jsで作成されたウェブアプリケーションです。 このウェブアプリケーションに、ルートの登録機能を追加しましたので、紹介します。 機能紹介 トップページにアクセスし、「マイルートを管理」ボタンをクリックします。 以下のように、ログインが求められますので、画面右上の「ログイン」ボタンからログインします。 ログイン後、以下のような一覧画面が表示されます。 「ルートをインポート」ボタンを押すと以下のダイアログが表示されます。 「サンプルデータをダウンロード」ボタンを押すと、以下のようなGeoJSON形式のサンプルデータがダウンロードされます。 { "type": "FeatureCollection", "name": "東京観光サンプルルート", "description": "東京駅から皇居への観光ルートのサンプルです", "features": [ { "type": "Feature", "id": "tokyo-station", "properties": { "text": "東京駅", "where": "東京都千代田区丸の内一丁目にある、東日本旅客鉄道・東海旅客鉄道・東京地下鉄の駅", "type": "point" }, "geometry": { "type": "Point", "coordinates": [ 139.7673068, 35.6809591 ] } }, { "type": "Feature", "id": "imperial-palace", "properties": { "text": "皇居", "where": "日本の天皇及び皇族の居所", "type": "point" }, "geometry": { "type": "Point", "coordinates": [ 139.7528, 35.6852 ] } } ] } このファイルをアップロードすると、以下のような編集画面が表示されます。 編集ボタン(鉛筆マーク)から、タイトルや説明文の編集、および個々のマーカーの編集が可能です。 以下のエクスポートボタンを押すと、 geojson.ioでの表示画面に遷移します。 エクスポートの他、ローカル環境にダウンロードすることも可能です。 補足 現在は技術検証を目的として単純な機能の提供のみになっていますが、今後、いろいろな機能拡張を進めたいと思います。 まとめ れきちずやGeoJSONの応用にあたり、参考になりましたら幸いです。

DToC: Dynamic Table of Contextsを試す

DToC: Dynamic Table of Contextsを試す

概要 DToC: Dynamic Table of Contextsを試す機会がありましたので、備忘録です。 https://www.leaf-vre.org/docs/features/dtoc 機械翻訳の結果は以下です。 セマンティックマークアップの威力と書籍のナビゲーション機能を融合させ、電子読書に革新をもたらします。従来の印刷書籍で長年親しまれてきた目次とキーワード索引という概観機能が、全文検索やタグベースのインデックス機能と動的に統合されることで、新たな読書体験を実現します。 最終的に、以下のような可視化を行うことができました。 https://dtoc.leaf-vre.org/view?document=https://dtoc-demo.vercel.app/P-III-b-1189/dtoc.json 対象データ 東洋文庫が所蔵するモリソンパンフレット「Marco Polo’s adventures : The greatest traveller the world has seen.」をサンプルデータとして利用しました。 https://www.toyo-bunko.org/open/show_detail_open.php?targetid=363479 https://www.toyo-bunko.org/morisonp2015/morisonpocr2016_showimg.php?tgfn=P-III-b-1189&tgfn2=01Geo01 背景 以下のワークショップに参加し、DToCの使用方法を教えてもらいました。 https://github.com/LEAF-VRE/dh2025_workshop 以下のチュートリアルも参考になりました。 https://www.leaf-vre.org/docs/training/tutorials/dtoc-tutorial mainとなるxmlを作成する まず、mainとなるxmlを作成します。以下のURLで確認できます。 https://dtoc-demo.vercel.app/P-III-b-1189/main.xml OCR Azure AI Document Intelligenceを用いてOCRを行いました。 https://azure.microsoft.com/en-us/products/ai-services/ai-document-intelligence 校正 & タグづけ OCR結果の校正と、人名や地名のタグ付与にあたり、「Google: Gemini 2.5 Pro」を使用しました。 https://deepmind.google/models/gemini/pro/ このように機械的な処理のため、誤りなどが含まれている可能性が高いですが、DToCで使用するためのTEI/XMLファイルを用意することができました。 index用のxmlを作成する 以下を参考にしました。 https://www.leaf-vre.org/docs/training/tutorials/dtoc-tutorial#step-2-create-an-index このindex作成にも「Google: Gemini 2.5 Pro」を使用し、先に作成したmain.xmlから機械的に作成しました。結果は以下です。 https://dtoc-demo.vercel.app/P-III-b-1189/index.xml JSONファイルを作成する DToCでロードするためのJSONファイルを作成します。この部分はGUIから行うことができました。最終的な結果は以下です。 https://dtoc-demo.vercel.app/P-III-b-1189/dtoc.json まず、以下にアクセスし、GitHubアカウントでログインします。 https://dtoc.leaf-vre.org/ 次に以下にアクセスします。 https://dtoc.leaf-vre.org/view そして、チュートリアル資料などを参考に、必要な項目を入力します。 Documentsには、前のプロセスで作成したXMLファイルのURLを入力します。 Corpus Partsでは、XMLファイルのどの部分を使用するか、を指定します。Curpus Partではmain.xmlのdivタグを、Curpus Indexではindex.xmlのdivタグをXPathで指定しました。 ...