ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
English
「画像コレクション管理」ツールの使い方ガイド

「画像コレクション管理」ツールの使い方ガイド

概要 IIIFの機能を簡単に試すことを目的とした、「画像コレクション管理」ツールを作成しました。 https://pocket.webcatplus.jp https://pocket.webcatplus.jp/ 本ツールの使い方について紹介します。 コレクション管理 コレクションの作成 ダッシュボードで「新規コレクション」ボタンをクリック 必要情報を入力: コレクション名 (必須): わかりやすい名前を付ける 説明 (任意): コレクションの内容を説明 公開設定 : 公開/非公開を選択 「作成」をクリック コレクションの編集 コレクション一覧から編集したいコレクションの「⋮」メニューをクリック 「編集」を選択 情報を更新して「保存」 コレクションの削除 コレクション一覧から削除したいコレクションの「⋮」メニューをクリック 「削除」を選択 確認ダイアログで「削除」をクリック ⚠️ 注意 : コレクションを削除すると、含まれるすべてのアイテムも削除されます アイテム(画像)管理 アイテムの追加 方法1: ドラッグ&ドロップ コレクションページを開く 「新規アイテム」ボタンをクリック 画像ファイルをドラッグ&ドロップエリアにドロップ タイトルと説明を入力 「作成して編集」をクリック 方法2: ファイル選択 「ファイルを選択」ボタンをクリック アップロードしたい画像を選択(複数選択可) タイトルと説明を入力 「作成して編集」をクリック 方法3: URLから追加 「URLから追加」タブを選択 画像のURLを入力 「追加」をクリック 方法4: IIIF画像の追加 「info.jsonから追加」タブを選択 IIIF info.jsonのURLを入力 「追加」をクリック アイテムの編集 アイテム一覧から編集したいアイテムをクリック 編集画面で以下の情報を更新: 基本情報 : タイトル、説明、公開設定 位置情報 : 緯度、経度、場所の名前 詳細情報 : 帰属表示、権利情報 追加情報 : カスタムフィールド(作成年、作者など) 「保存」をクリック ...

TEI/XMLファイルをS3互換のオブジェクトストレージでホストする

TEI/XMLファイルをS3互換のオブジェクトストレージでホストする

概要 TEI/XMLファイルをS3互換のオブジェクトストレージでホストする機会がありましたので、備忘録です。具体的には、mdx Iのオブジェクトストレージを対象にします。 https://mdx.jp/mdx1/p/about/system 背景 TEI/XMLファイルを読み込み、その内容を可視化するウェブアプリケーション(Next.js)を構築します。この時、ファイル数やサイズが小さい場合は、publicフォルダに格納していましたが、これらが大きくなった場合、別の場所でホストすることを考えました。 場所の選択肢は多々ありますが、今回はS3互換であるmdx Iのオブジェクトストレージを対象にします。 GUIを用いたオブジェクトストレージへのファイルアップロード オブジェクトストレージへTEI/XMLファイルをGUI経由でアップロードする方法も多々あります。その中で、これまではCyberduckを使用する方法や、GakunNin RDMを使用する方法などを紹介しました。 一方、今回の事例では、TEI/XML以外のコンテンツをDrupalで管理していました。そこで、Drupalとオブジェクトストレージを接続し、ユーザはDrupalの操作で完結できるようにしました。 Drupalとオブジェクトストレージの接続 以下のモジュールを使用します。 https://www.drupal.org/project/s3fs インストール後、環境設定のページ/admin/configから、S3 File Systemを選択します。 そして、アクセスキーや秘密鍵を登録し、さらにS3のバケット名を登録します。 またAdvanced Configuration OptionsのCustom Host Settingsにおいて、https://s3ds.mdx.jpを入力します。 これでオブジェクトストレージとの接続設定は完了です。 その後、各コンテンツタイプのフィード設定において、アップロード先として「S3 File System」を選択します。 また、今回はTEI/XMLファイルがアップロード対象となるため、「許可されている拡張子」として、xmlを入力します。 この結果、DrupalのGUIを介してアップロードしたTEI/XMLファイルが、mdx Iのオブジェクトストレージに格納されるようになりました。 (参考)DrupalのJSON:APIを用いたファイルの一括アップロード TEI/XMLの初期登録にあたり、Pythonを用いた一括登録を行いました。JSON:APIを用いたファイルの一括アップロードの方法は、以下の記事などが参考になりました。 https://www.drupal.org/node/3024331 一例ですが、以下のようなスクリプトで実現できました。 import requests import json import os from dotenv import load_dotenv from glob import glob from tqdm import tqdm 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("DRUPAL_USERNAME") self.PASSWORD = os.getenv("DRUPAL_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 upload_file(self, type, uuid, field, file_path, verbose=False): url = f"{self.DRUPAL_BASE_URL}/jsonapi/node/{type}/{uuid}/{field}" # ファイル名を取得 filename = os.path.basename(file_path) # ファイルをバイナリモードで読み込む with open(file_path, 'rb') as f: file_data = f.read() headers = self.headers.copy() headers['Content-Type'] = 'application/octet-stream' headers['Content-Disposition'] = f'attachment; filename="{filename}"' # ファイルをアップロード response = requests.post(url, headers=headers, cookies=self.session_cookies, data=file_data) if response.status_code == 200: if verbose: print(f"ファイルアップロード成功: {filename}") else: print(f"ファイルアップロード失敗: {response.status_code} {response.text}") すでに対象コンテンツが作成済みで、例えばfield_fileといったフィールドにファイルをアップロードする目的で使用することができます。 ...

MDX.jpのオブジェクトストレージに対するIPアドレス制限の実装方法

MDX.jpのオブジェクトストレージに対するIPアドレス制限の実装方法

概要 MDX.jpのオブジェクトストレージに対するIPアドレス制限の実装方法を調べました。以下、動作確認を行なった上で、AIが記事を執筆しました。 はじめに 本記事では、MDX.jpが提供するDDN EXAScaler S3互換オブジェクトストレージサービスにおいて、特定のIPアドレスからのみアクセスを許可する設定方法について解説します。 オブジェクトストレージのセキュリティレイヤー DDN EXAScaler S3互換ストレージには、主に以下の3つのセキュリティレイヤーがあります: アクセスキーとシークレットキー :基本的な認証情報 バケットポリシー :バケットレベルでのアクセス制御 アクセス制御リスト(ACL) :オブジェクトレベルでのアクセス制御 この中で、IPアドレス制限を実装するには「バケットポリシー」を利用します。 バケットポリシーによるIPアドレス制限の設定手順 1. ポリシーJSONファイルの作成 まず、以下のようなJSONファイル(例:mdx.json)を作成します: { "Version": "2008-10-17", "Statement": [ { "Sid": "BucketName", "Effect": "Allow", "Principal": { "DDN": ["*"] }, "Action": [ "s3:ListBucket", "s3:GetObject" ], "Resource": "BucketName", "Condition": { "IpAddress": { "aws:SourceIp": [ "192.168.1.1/32", "203.0.113.0/24" ] } } } ] } ポリシーの主な要素: Version : ポリシー構文のバージョン Sid : ポリシーステートメントの識別子(任意の名前) Effect : 許可または拒否(“Allow"または"Deny”) Principal : このポリシーが適用されるユーザー(DDN EXAScalerでは"DDN"を使用) Action : 許可または拒否するアクション Resource : ポリシーが適用されるリソース(バケット名) Condition : 条件(ここでIPアドレス制限を設定) 2. ポリシーの適用 s3cmdツールを使用して、作成したポリシーをバケットに適用します: ...

mdx Iのオブジェクトストレージに対するproxyサーバの構築

mdx Iのオブジェクトストレージに対するproxyサーバの構築

概要 mdx Iのオブジェクトストレージに対するproxyサーバの構築に関する備忘録です。 背景 mdx Iの利用手引きにおいて、以下のように説明されています。 https://docs.mdx.jp/ja/index.html#オブジェクトストレージ mdxが提供するS3データサービス(DDN EXAScaler S3 Data Service)で取り扱うAPI仕様を記載したDataDirect Networks社のマニュアルです。 Tipsのオブジェクトストレージの利用方法例 と合わせてご確認ください。 https://docs.mdx.jp/ja/_downloads/b5d961f2c152387fa10ed951d5278f47/S3 Data Services 5.2.7 API Reference Guide.pdf こちらをGoogle NotebookLMに読み込ませ、corsの実装状況について確認しました。以下が回答です。 回答 資料 でBucket CORS Featureが未実装 であることが明記されているため、EXAScaler Access S3 APIに対して、ウェブブラウザ上で動作するJavaScriptなどから直接、異なるオリジン (例えば、APIのエンドポイントとは異なるドメインで提供されているウェブサイトのJavaScript)を通してリクエストを行うと、CORS(Cross-Origin Resource Sharing)の問題が発生し、通常はリクエストがブロックされます 。 これは、ウェブブラウザのSame-Origin Policy というセキュリティ上の仕組みによるものです。異なるオリジンからのリソースへのアクセスは、サーバー側が明示的に許可しない限り制限されます。CORSは、この許可の仕組みを提供するものですが、EXAScaler Access S3においては、この機能がまだ実装されていないため、サーバー側からのCORSヘッダーなどのレスポンスがなく、ブラウザはクロスオリジンリクエストを拒否する と考えられます。 したがって、プロキシサーバー などを利用して、クライアントサイドのリクエストを一旦プロキシサーバーに送り、そこからEXAScaler Access S3 APIにリクエストを行うことで、オリジンが一致するように見せかけるなどの回避策が必要になる場合があります。プロキシサーバーは、APIからのレスポンスに必要なヘッダーを付与する役割を担うこともできます。 ただし、これはCORSの問題を回避するための一つの一般的な方法であり、他にもサーバーサイドでAPIを公開する際にオリジンを一致させるなどの方法も考えられます。重要なのは、EXAScaler Access S3 API自体がCORSの仕組みをサポートしていない ため、クライアントサイドから直接クロスオリジンリクエストを行う際には、何らかの対策が必要になるということです。 対策 理解が間違っている点もあるかもしれませんが、上記の回答から、mdx Iのオブジェクトストレージに対するproxyサーバの構築を行うこととしました。 構築したproxyサーバのリポジトリは以下です。 https://github.com/nakamura196/s3-proxy 例えば、以下で指定したバケット上のファイルにアクセスできます。 https://s3-proxy.vercel.app/public/CETEIcean.css 一方、以下が直接アクセスした例です。 https://s3ds.mdx.jp/satoru196/public/CETEIcean.css 前者では、以下のようなレスポンスヘッダーが確認でき、CORSの設定がなされていることが確認できます。 access-control-allow-origin: * age: 0 cache-control: public, max-age=0, must-revalidate content-encoding: br content-type: text/css date: Sun, 23 Mar 2025 03:11:27 GMT etag: W/“3d5c-psb8jsgRM3DKYLgMVwi7Ns/AIhg” server: Vercel strict-transport-security: max-age=63072000; includeSubDomains; preload x-powered-by: Express x-vercel-cache: MISS x-vercel-id: hnd1::iad1::zbdgm-1742699486592-2b286aacd062 実装 Expressを用いて、以下のように実装しました。aws-sdkについては、AWS SDK for JavaScript v3に移行する必要があるようなので、この点はご注意ください。 ...

GakuNin RDMのストレージに、mdx.jpのオブジェクトストレージを追加する

GakuNin RDMのストレージに、mdx.jpのオブジェクトストレージを追加する

概要 GakuNin RDMのストレージに、mdx.jpのオブジェクトストレージを追加する方法です。 手順 mdx.jp mdx.jpのオブジェクトストレージの利用申請を行い、アクセスキーとシークレットキーを控えます。 GakuNin RDM S3 Compatible Storageを有効にします。 S3互換サービスとしてmdx S3DSを選択して、控えたアクセスキーとシークレットキーを入力します。 バケットの一覧が表示されるので、接続したいバケットを選択します。 結果として、「ファイル」メニューからアクセスできるストレージに、mdx.jpのオブジェクトストレージが追加されます。 今後、ドラッグ&ドロップにより、ファイルのアップロードなどを行うことができます。 まとめ GakuNin RDMとmdx.jpのオブジェクトストレージの接続にあたり、参考になりましたら幸いです。

Omeka Sのファイルをmdx.jpのオブジェクトストレージに保存する

Omeka Sのファイルをmdx.jpのオブジェクトストレージに保存する

概要 Omeka Sのファイルをmdx.jpのオブジェクトストレージに保存する方法に関する備忘録です。 ベースとするモジュール Amazon S3との連携を可能にする以下のモジュールをベースとします。 https://omeka.org/s/modules/AmazonS3/ 本モジュールでは、Omeka Sで取り扱う画像や動画といったメディアのファイルをAmazon S3に保存するための拡張機能を提供します。 一方、endpointの指定ができないため、mdx.jpのオブジェクトストレージなどを対象にすることはできませんでした。 モジュールのカスタマイズ 上述した背景を踏まえて、Amazon S3以外のオブジェクトストレージを利用できるように、モジュールをカスタマイズしました。カスタマイズした結果は、以下のリポジトリで公開しています。 https://github.com/nakamura196/Omeka-S-module-AmazonS3 なお、カスタマイズについては、エディタとしてCursorを使用し、s3互換のオブジェクトストレージにも対応したいという依頼をclaude-3.7-sonnetに提出し、その結果を反映しています。 結果、上記のモジュールを使用することにより、Omeka Sで登録したメディアが以下のようなURLでアクセス可能になりました。 https://s3ds.mdx.jp/<バケット名>/large/3e0a78e1cbc239f37cfff0e777c40c2f9b2f5c92.jpg 以下は、filesディレクトリを、mdx.jpに接続したCyberduckで表示した例です。 モジュールの設定内容は以下のとおりです。カスタムエンドポイントURLという項目が追加されており、https://s3ds.mdx.jpを指定することで、mdx.jpのオブジェクトストレージを利用できるようになりました。 なお、上記の画面キャプチャで表示されているとおり、mdx.jpのオブジェクトストレージにファイルが保存される設定をしても、現時点ではWrong region. Please use region of a bucket:と表示されてしまいます。この点は、今後修正予定です。 モジュールのインストール 今回フォークして作成したカスタムモジュールをインストールするには、以下の手順を踏む必要があります。 cd <モジュールが格納されているディレクトリ> git clone https://github.com/nakamura196/Omeka-S-module-AmazonS3 AmazonS3 cd AmazonS3 composer install --no-dev Omeka Sにおいて、ソースからモジュールを使用するには、おおよそ共通して上記のような手続きが必要になります。 参考 Omeka Sのモジュールにおいて、同様の機能を提供するものとして、Any Cloudがあります。 https://github.com/HBLL-Collection-Development/omeka-s-any-cloud こちらもAmazon S3との接続機能を提供しており、またカスタイズを行う必要がなく、AWS Endpointを入力する項目が提供されていました。 ただ、これらの項目に先述したmdx.jpのオブジェクトストレージの情報を入力したところ、アイテムなどを登録する画面で以下のエラーが表示されました。 原因や対処方法については引き続き調査したいと思いますが、このエラーが遭遇したため、Any Cloudではなく、Amazon S3モジュールをカスタマイズする選択を行いました。 まとめ 2025年度からmdx.jpのオブジェクトストレージは無料で使用可能になるということで、デジタルアーカイブにおける公開画像の格納先や、また長期保存のためのストレージとしても有効な選択肢になるかと思います。 https://mdx.jp/mdx1/news/4839 デジタルアーカイブの構築や活用にあたり、参考になりましたら幸いです。

mdx.jpのオブジェクトストレージとIIP Image(IIIF Image Server)を使ってIIIF画像を配信する

mdx.jpのオブジェクトストレージとIIP Image(IIIF Image Server)を使ってIIIF画像を配信する

概要 mdx.jpのオブジェクトストレージとIIP Image(IIIF Image Server)を使ってIIIF画像を配信する試行の備忘録です。 以下の記事の続きです。 Docker版IIP Image 以下で、IIPImage serverのDocker Imageが公開されていましたので、こちらを使います。 https://hub.docker.com/r/iipsrv/iipsrv 以下の記事などを参考に、Dockerをインストールします。 https://qiita.com/Marron-chan/items/570c7c7baaae3b4d6b11 実行 前回の記事に倣い、以下のようにmdx.jpのオブジェクトストレージをマウントします。 s3fs satoru196 ~/s3mount -o passwd_file=~/.passwd-s3fs -o url=https://s3ds.mdx.jp -o use_path_request_style -o allow_other 注意点として、前回の記事から、-o allow_otherを追加しています。これを追加しないと、次のコンテナ起動時に以下のエラーが発生しました。 docker: Error response from daemon: error while creating mount source path '~/s3mount/iip/images': mkdir ~/s3mount: file exists Run 'docker run --help' for more information -o allow_otherオプションを追加した上で、以下を実行します。無事に起動しました。 docker run -it -p 9000:9000 -p 8080:80 -v ~/s3mount/iip/images/:/images --rm iipsrv/iipsrv <-----------------------------------> Thu Mar 6 22:35:43 2025 IIPImage Server. Version 1.2 *** Ruven Pillay <ruven@users.sourceforge.net> *** Verbosity level set to 5 Running in standalone mode on socket: 0.0.0.0:9000 with backlog: 2048 Setting maximum image cache size to 10MB Setting filesystem prefix to '/images/' Setting filesystem suffix to '' Setting default JPEG quality to 75 Setting default PNG compression level to 1 Setting default WebP compression level to 50 Setting maximum CVT size to 5000 Setting HTTP Cache-Control header to 'max-age=86400' Setting 3D file sequence name pattern to '_pyr_' Setting default IIIF Image API version to 3 Setting Allow Upscaling to true Setting ICC profile embedding to true Setting up JPEG2000 support via OpenJPEG Setting image processing engine to CPU processor OpenMP enabled for parallelized image processing with 2 threads Setting URI mapping to iiif=>IIIF. Supported protocol: IIIF Memcached support enabled. Connected to servers: 'localhost' with timeout 86400 Initialisation Complete. <-----------------------------------> そして、今回の設定では、オブジェクトストレージの/satoru196/iip/imagesにtiled multi-resolution pyramid TIFFファイルを格納し、以下のようなURLでアクセスできることを確認します。 ...

Alfrescoのファイルに対して、Archivematicaを使ってAIPを作成する

Alfrescoのファイルに対して、Archivematicaを使ってAIPを作成する

概要 Alfrescoのファイルに対して、Archivematicaを使ってAIPを作成する方法の一例です。 以下が成果物のデモ動画です。 https://youtu.be/7WCO7JoMnWc システム構成 今回は以下のようなシステム構成とします。複数のクラウドサービスを利用していることに特に意味はありません。 Alfrescoは、以下の記事を参考に、Azure上に構築したものを使用します。 Archivematicaとオブジェクトストレージはmdx.jpを使用し、分析環境はGakuNin RDMを使用します。 オブジェクトストレージへのファイルアップロード Alfrescoからファイルをダウンロード Alfrescoからのファイルダウンロードにあたっては、REST APIを使用します。 https://docs.alfresco.com/content-services/6.0/develop/rest-api-guide/ OpenAPIに準拠しており、以下などを参考にしました。 https://api-explorer.alfresco.com/api-explorer/ 例えば以下により、Alfrescoのユーザ名とパスワード、およびホスト名を環境変数から読み込み、メタデータの取得やコンテンツのダウンロードを行うことができました。 # %% ../nbs/00_core.ipynb 3 from dotenv import load_dotenv import os import requests from base64 import b64encode # %% ../nbs/00_core.ipynb 4 class ApiClient: def __init__(self, verbose=False): """Alfresco API Client Args: verbose (bool): デバッグ情報を出力するかどうか """ self.verbose = verbose # .envの読み込み load_dotenv(override=True) # 環境変数の取得 self.user = os.getenv('ALF_USER') self.password = os.getenv('ALF_PASSWORD') self.target_host = os.getenv('ALF_TARGET_HOST') self._debug("環境変数の設定:", { "user": self.user, "password": "*" * len(self.password) if self.password else None, "target_host": self.target_host }) # Basic認証のヘッダーを作成 credentials = f"{self.user}:{self.password}" encoded_credentials = b64encode(credentials.encode()).decode() self.headers = { 'accept': 'application/json', 'authorization': f'Basic {encoded_credentials}' } self._debug("ヘッダーの設定:", { "accept": self.headers['accept'], "authorization": "Basic ***" }) def _debug(self, message: str, data: dict = None): """デバッグ情報を出力する Args: message (str): メッセージ data (dict, optional): 追加のデータ """ if self.verbose: print(f"🔍 {message}") if data: for key, value in data.items(): print(f" - {key}: {value}") def get_nodes_nodeId(self, node_id: str): """ノードIDでノード情報を取得する Args: node_id (str): ノードID Returns: dict: ノード情報 """ url = f"{self.target_host}/alfresco/api/-default-/public/alfresco/versions/1/nodes/{node_id}" self._debug("APIリクエスト:", {"url": url}) try: response = requests.get( url, headers=self.headers, timeout=float(30) ) response.raise_for_status() return response.json() except requests.exceptions.Timeout: self._debug("エラー:", {"type": "timeout", "message": "リクエストがタイムアウトしました"}) return None except requests.exceptions.RequestException as e: self._debug("エラー:", {"type": "request", "message": str(e)}) return None def get_nodes_nodeId_content(self, node_id: str, output_path: str): """ノードのコンテンツを取得する Args: node_id (str): ノードID output_path (str): 出力パス """ url = f"{self.target_host}/alfresco/api/-default-/public/alfresco/versions/1/nodes/{node_id}/content" self._debug("APIリクエスト:", { "url": url, "output_path": output_path }) response = requests.get(url, headers=self.headers) binary_data = response.content os.makedirs(os.path.dirname(output_path), exist_ok=True) with open(output_path, "wb") as file: file.write(binary_data) self._debug("ファイル保存完了:", { "size": len(binary_data), "path": output_path }) オブジェクトストレージにファイルをアップロード boto3と、オブジェクトストレージのENDPOINT_URL、ACCESS_KEY、SECRET_KEYおよびBUCKET_NAMEなどを使用して、ファイルのアップロード(とダウンロード)を行います。 ...

DataverseのデータをArchivematicaで処理する

DataverseのデータをArchivematicaで処理する

概要 DataverseのデータをArchivematicaで処理する流れを確認しましたので、備忘録です。 背景 ArchivematicaではDataverseのデータを入力する機能を提供しています。 https://www.archivematica.org/en/docs/archivematica-1.17/user-manual/transfer/dataverse/ 本機能について、以下の講演会で教えていただいたので、実際に試してみました。 https://www.kulib.kyoto-u.ac.jp/bulletin/1402322 Dataverse 以下の記事でも使用したDemo Dataverseを使用します。 以下のデータをアップロードしました。 https://demo.dataverse.org/dataset.xhtml?persistentId=doi:10.70122/FK2/IHQZL3 ここから画像データそのものと、JSONデータをダウンロードします。Metadataタブに移動し、Export MetadataからJSONを選択します。 以下はJSONファイルの一部ですが、metadataBlocksにメタデータ、filesに画像ファイルの情報が記載されています。 { "metadataBlocks": { "citation": { "displayName": "Citation Metadata", "name": "citation", "fields": [ { "typeName": "title", "multiple": false, "typeClass": "primitive", "value": "nakamura196" }, { "typeName": "author", "multiple": true, "typeClass": "compound", "value": [ { "authorName": { "typeName": "authorName", "multiple": false, "typeClass": "primitive", "value": "Nakamura, Satoru" }, "authorAffiliation": { "typeName": "authorAffiliation", "multiple": false, "typeClass": "primitive", "value": "https://ror.org/057zh3y96", "expandedvalue": { "scheme": "http://www.grid.ac/ontology/", "termName": "The University of Tokyo", "@type": "https://schema.org/Organization" } } } ] }, { "typeName": "datasetContact", "multiple": true, "typeClass": "compound", "value": [ { "datasetContactName": { "typeName": "datasetContactName", "multiple": false, "typeClass": "primitive", "value": "Nakamura, Satoru" }, "datasetContactEmail": { "typeName": "datasetContactEmail", "multiple": false, "typeClass": "primitive", "value": "na.kamura.1263@gmail.com" } } ] }, { "typeName": "dsDescription", "multiple": true, "typeClass": "compound", "value": [ { "dsDescriptionValue": { "typeName": "dsDescriptionValue", "multiple": false, "typeClass": "primitive", "value": "My First Dataset" } } ] }, { "typeName": "subject", "multiple": true, "typeClass": "controlledVocabulary", "value": [ "Arts and Humanities" ] }, { "typeName": "depositor", "multiple": false, "typeClass": "primitive", "value": "Nakamura, Satoru" }, { "typeName": "dateOfDeposit", "multiple": false, "typeClass": "primitive", "value": "2025-01-19" } ] } }, "files": [ { "label": "nakamura196.jpg", "restricted": false, "version": 1, "datasetVersionId": 281093, "dataFile": { "id": 2514724, "persistentId": "doi:10.70122/FK2/IHQZL3/B7JVQS", "pidURL": "https://doi.org/10.70122/FK2/IHQZL3/B7JVQS", "filename": "nakamura196.jpg", "contentType": "image/jpeg", "friendlyType": "JPEG Image", "filesize": 53656, "storageIdentifier": "s3://demo-dataverse-org:1948154820d-63733533ea7c", "rootDataFileId": -1, "md5": "72f08a8b07bacbe3b5cf021910fd26dc", "checksum": { "type": "MD5", "value": "72f08a8b07bacbe3b5cf021910fd26dc" }, "tabularData": false, "creationDate": "2025-01-19", "publicationDate": "2025-01-19", "fileAccessRequest": true } } ] } データの準備 Dataverseのサンプルデータは以下に格納されています。 ...

mdx.jpのオブジェクトストレージに保存したIIIFマニフェストファイルをNestJSから利用する

mdx.jpのオブジェクトストレージに保存したIIIFマニフェストファイルをNestJSから利用する

概要 mdx.jpのオブジェクトストレージに保存したIIIFマニフェストファイルをNestJSから利用する機会がありましたので、備忘録です。 背景 mdx.jpのオブジェクトストレージに関して、簡単に確認したところ、corsの設定ができず、mdx.jpのオブジェクトストレージにアップロードしたIIIFマニフェストファイルを他のビューアから利用することは難しいようでした。 https://tech.ldas.jp/ja/posts/ad76f58db4e098/#注意(corsの許可) そこで、NestJSからオブジェクトストレージにアップロードしたIIIFマニフェストファイルをロードして返却します。 ソースコード 以下のリポジトリからご確認いただけます。 https://github.com/nakamura196/nestjs-iiif 以下のような環境変数を用意します。mdx.jpのオブジェクトストレージを使用するため、S3_ENDPOINTにhttps://s3ds.mdx.jpを与えます。 S3_ENDPOINT=https://s3ds.mdx.jp S3_REGION=us-east-1 S3_ACCESS_KEY_ID=xxx S3_SECRET_ACCESS_KEY=xxx S3_BUCKET_NAME=xxx そして、@aws-sdk/client-s3を利用して、以下のように、オブジェクトストレージ上のIIIFマニフェストファイルをダウンロードして返却します。 // src/s3.service.ts import { Injectable } from '@nestjs/common'; import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; import { Readable } from 'stream'; import * as dotenv from 'dotenv'; dotenv.config(); @Injectable() export class S3Service { private readonly s3Client: S3Client; constructor() { this.s3Client = new S3Client({ region: process.env.S3_REGION, endpoint: process.env.S3_ENDPOINT, forcePathStyle: true, // パススタイルを有効化(多くの互換ストレージで必要) credentials: { accessKeyId: process.env.S3_ACCESS_KEY_ID, secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, }, }); } async getJsonFile(key: string): Promise<any> { const bucket = process.env.S3_BUCKET_NAME; if (!bucket) { throw new Error('S3_BUCKET_NAME is not set in environment variables.'); } const command = new GetObjectCommand({ Bucket: bucket, Key: key }); const response = await this.s3Client.send(command); const stream = response.Body as Readable; const chunks: Uint8Array[] = []; for await (const chunk of stream) { chunks.push(chunk); } const fileContent = Buffer.concat(chunks).toString('utf-8'); return JSON.parse(fileContent); } } まとめ mdx.jpのオブジェクトストレージに保存したIIIFマニフェストファイルの利用にあたり、参考になりましたら幸いです。

Archivematicaのtransferにおいて、processing_configを使う

Archivematicaのtransferにおいて、processing_configを使う

概要 Archivematicaのtransferにおいて、processing_configの使用方法について説明します。 背景 Archivematicaのtransferにおいて、processing_configを選択することができます。以下では、「automated」「default」「mdx」の3つから選択できることがわかります。 これは、「Administration」メニューにおける「Processing configuration」において設定することができます。 例えば以下は、mdx.jpのs3互換ストレージとやりとりすることを前提とした設定例です。 以下のように、「Store AIP location」に対象ストレージを選択することで、このprocessing configurationを選択した際には、当該ストレージにAIPが保存されることになります。 APIからの利用 APIからもこの設定を利用することができます。 以下のBETA版として提供されているものになりますが、/api/v2beta/packageを利用することができます。 https://www.archivematica.org/en/docs/archivematica-1.16/dev-manual/api/api-reference-archivematica/#package processing_configオプションを設定することで、APIからの利用においても、入力データごとに、AIPやDIPの出力フォルダを変更することができます。 まとめ Archivematicaの利用にあたり、参考になりましたら幸いです。

YOLOv11xと日本古典籍くずし字データセットを用いた文字の検出モデルの構築

YOLOv11xと日本古典籍くずし字データセットを用いた文字の検出モデルの構築

概要 YOLOv11xと日本古典籍くずし字データセットを用いた文字の検出モデルの構築を行う機会がありましたので、備忘録です。 http://codh.rois.ac.jp/char-shape/ 参考 過去に、YOLOv5を用いて同様のことを行いました。以下のspacesで動作デモや学習済みモデルをご確認いただけます。 https://huggingface.co/spaces/nakamura196/yolov5-char 以下は、「国宝 金沢文庫文書データベース」の公開画像に対する適用例です。 YOLOv11を用いることで、文字検出の精度向上を狙うことが目的です。 データセットの作成 「日本古典籍くずし字データセット」をダウンロードし、yoloで求められる形式に整形します。 形式は以下などで確認することができます。 https://github.com/ultralytics/hub/tree/main/example_datasets/coco8 画像のサイズを1280x1280に設定 以下のUltralytics HUBを使用しました。 https://hub.ultralytics.com/ 以下が学習結果です。 テストデータに対して適用したところ、良い精度がでる画像データ(例:「『源氏物語』(東京大学総合図書館所蔵)」)もあれば、 あまり良い精度がでない画像データ(例:「国宝 金沢文庫文書データベース」)もありました。 画像のサイズを640x640に設定 エポック数が10の場合 エポック数が10の場合は、エポック数が10の場合、学習が完全に収束していない可能性がありました。 一方、エポック数が少ないにも関わらず、テストデータに対しては、1280x1280のものより良い結果を示すようでした。 エポック数が100の場合 from ultralytics import YOLO # YOLOv8の分類モデルをロード model = YOLO('yolo11x.pt') # Nanoサイズの分類モデル # データセットとトレーニング設定 model.train( data='/home/mdxuser/yolo/chars_640_split/data.yaml', # データセットのパス epochs=100, # エポック数 # imgsz=224, # 入力画像サイズ batch=24 # バッチサイズ(オプション) ) バッチサイズが16(デフォルト)では、GPUメモリの使用率が低く、32に設定すると、OutOfMemoryErrorになってしまいました。 torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 4.49 GiB. GPU 0 has a total capacity of 39.39 GiB of which 4.46 GiB is free. Including non-PyTorch memory, this process has 34.92 GiB memory in use. Of the allocated memory 31.86 GiB is allocated by PyTorch, and 2.49 GiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True to avoid fragmentation. See documentation for Memory Management (https://pytorch.org/docs/stable/notes/cuda.html#environment-variables) バッチサイズが24 ...

mdx.jpを用いてYOLOv11のクラス分類(くずし字認識)の学習を試す

mdx.jpを用いてYOLOv11のクラス分類(くずし字認識)の学習を試す

概要 mdx.jpを用いてYOLOv11のクラス分類(くずし字認識)の学習を行う機会がありましたので、備忘録です。 データセット 以下の「くずし字データセット」を対象にします。 http://codh.rois.ac.jp/char-shape/book/ データセットの作成 yoloの形式に合致するようにデータセットを整形します。まず、書名ごとに分かれているデータをフラットにマージします。 #| export class Classification: def create_dataset(self, input_file_path, output_dir): # "../data/*/characters/*/*.jpg" files = glob(input_file_path) # output_dir = "../data/dataset" for file in tqdm(files): cls = file.split("/")[-2] output_file = f"{output_dir}/{cls}/{file.split('/')[-1]}" if os.path.exists(output_file): continue # print(f"Copying {file} to {output_file}") os.makedirs(f"{output_dir}/{cls}", exist_ok=True) shutil.copy(file, output_file) 次に、以下のようなスクリプトにより、データセットを分割します。 def split(self, input_dir, output_dir, train_ratio = 0.7, val_ratio = 0.15): if os.path.exists(output_dir): shutil.rmtree(output_dir) # クラスディレクトリの取得 classes = [d for d in os.listdir(input_dir) if os.path.isdir(os.path.join(input_dir, d))] # データを分割して保存 for cls in tqdm(classes): class_dir = os.path.join(input_dir, cls) files = [os.path.join(class_dir, f) for f in os.listdir(class_dir) if os.path.isfile(os.path.join(class_dir, f))] # シャッフルして分割 random.shuffle(files) train_end = int(len(files) * train_ratio) val_end = int(len(files) * (train_ratio + val_ratio)) train_files = files[:train_end] val_files = files[train_end:val_end] test_files = files[val_end:] # 保存ディレクトリを作成 for split, split_files in zip(["train", "val", "test"], [train_files, val_files, test_files]): split_dir = os.path.join(output_dir, split, cls) os.makedirs(split_dir, exist_ok=True) # ファイルをコピー for file in split_files: shutil.copy(file, os.path.join(split_dir, os.path.basename(file))) print("データの分割が完了しました。") 結果、1,086,326画像のデータセットが作成されました。 ...

mdx.jpの1GPUパックとOllamaを使ってローカルLLMを実行する

mdx.jpの1GPUパックとOllamaを使ってローカルLLMを実行する

概要 mdx.jpの1GPUパックとOllamaを使ってローカルLLMを実行する機会がありましたので、備忘録です。 https://mdx.jp/mdx1/p/guide/charge 参考 以下の記事を参考にしました。 https://highreso.jp/edgehub/machinelearning/ollamainference.html モデルのダウンロード ここでは、llama3.1:70bを対象にします。 ダウンロード完了後、以下のように選択可能となります。 使用例 以下の『渋沢栄一伝記資料』を使用します。 https://github.com/shibusawa-dlab/lab1 APIの利用 以下に記載がありました。 https://docs.openwebui.com/api/ 以下でJWTトークンとは別に、APIキーを発行します。 以下が実行例です。 import requests import json text = '''六月十四日 日 晴 風ナクシテ暑気昨日ニ比シテ少ク加フルヲ覚フ 朝来少シク風邪気ナルニヨリ晏起、 八時 洗面ヲナス、後、六孫王宮ノ神官又ハ同志社員 安藤 氏等来訪ス、 十時 大阪支店長 野口 、 神戸 杉田 、 名古屋 清水 及 西京 支店長 中川 、其他 小林 、 片野 、 前原 等ノ諸氏ヲ伴ヒ 嵐山 ニ抵リ、三軒屋ニテ午飧シ、船ヲ浮ヘテ大江川《(堰)》ヲ遡ル、船中囲碁ノ興アリ、 嵐山 ノ緑葉少シク繁茂ニ過ルモ両岸ニハ山花咲乱レテ頗ル風致アリ、 午後四時 過 玉川楼 ニ帰宿ス、今朝、 尾崎 司法大臣ノ秘書 黒田 氏来ル、又、 林 和太郎 氏( 桂 氏ノ父)来話ス、 午前十時 ヨリ各支店主任ト共ニ 嵐山 ニ抵リ三軒屋ニテ午飧ス、後、大江川《(大堰川)》ニ船ヲ浮ヘ、 午後四時 帰宿ス、後、 玉川楼 ニ於テ晩飧会ヲ開ク、種々ノ余興アリ、夜 十時 散会ス、 中井 三郎兵衛 氏モ来会ス''' APIKEY = "sk-xxxx" url = "http://localhost:8080/api/chat/completions" headers = { "Authorization": f"Bearer {APIKEY}", "Content-Type": "application/json" } thres = 300 data = { "model": "llama3.1:70b", "messages": [ { "role": "user", "content": f"次のテキストは渋沢栄一の日記の一部です。テキストを{thres}字程度に要約してください。要約文のみを改行せずに返してください。句読点を適宜使用してください。\n\n{text}" } ] } response = requests.post(url, headers=headers, data=json.dumps(data)) # レスポンスの表示 print(response.status_code) print(response.json()) 結果、以下が得られました。ただし、結果が返却されるまでに60s弱かかってしまいました。 ...

Archivematicaにmdx.jpのオブジェクトストレージを追加する

Archivematicaにmdx.jpのオブジェクトストレージを追加する

概要 Archivematicaにmdx.jpのオブジェクトストレージを追加する機会がありましたので、備忘録です。 背景 以下の記事で、Amazon S3をArchivematicaの処理対象およびAIPの保存先に設定する方法を記載しました。 今回は、この手順をベースとしつつ、mdx.jpのオブジェクトストレージを接続してみます。 設定方法 以下のように設定します。 S3 Endpoint URLには、https://s3ds.mdx.jpを設定します。 Access Key ID to authenticateとSecret Access Key to authenticate withには、以下で得られるアクセスキーと秘密鍵を使用します。 結果 結果、以下のように、mdx.jpのオブジェクトストレージを入出力ストレージとして利用できるようになりました。これにより、AIPやDIPをmdx.jpのオブジェクトストレージに保存することができます。 補足 以下の記事で記載した方法を参考に、GakuNin RDMとmdx.jpのオブジェクトストレージを接続することができます。 これにより、GakuNin RDM上でAIPやDIPの確認が可能となります。これにより、GakuNin RDMのBinderHubを用いたAIPの分析や可視化が可能となります。 可視化例として、ArchivematicaのMETSファイルを人間に優しい方法で探索可能とするMETSFlaskの応用などが考えられます。 まとめ Archivematica, GakuNin RDM, mdx.jpなどの連携にあたり、参考になりましたら幸いです。

mdx.jpのオブジェクトストレージとCantaloupe Image Serverを使ってIIIF画像を配信する

mdx.jpのオブジェクトストレージとCantaloupe Image Serverを使ってIIIF画像を配信する

概要 mdx.jpのオブジェクトストレージとIIIFイメージサーバの一つであるCantaloupe Image Serverを使ってIIIF画像を配信する方法に関する備忘録です。 背景 以下の記事で、mdx.jpのオブジェクトストレージを使った画像の配信方法について紹介しました。 また以下の記事で、Cantaloupe Image Serverで、Amazon S3に格納した画像を配信する方法について紹介しました。 これらを組み合わせることにより、デジタルアーカイブにおけるIIIF画像配信コストの課題の解決を目指します。 方法 以下の記事で紹介したDocker版Cantaloupeを使用します。 以下のリポジトリから、ソースコードをダウンロードいただけます。 https://github.com/nakamura196/docker_cantaloupe_s3 同梱されている.env.sampleを.envファイルにリネームし、設定を変更します。 # aws s3 CANTALOUPE_S3SOURCE_ENDPOINT= # mdx.jp # CANTALOUPE_S3SOURCE_ENDPOINT=https://s3ds.mdx.jp CANTALOUPE_S3SOURCE_ACCESS_KEY_ID= CANTALOUPE_S3SOURCE_SECRET_KEY= CANTALOUPE_S3SOURCE_REGION= CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_BUCKET_NAME= ポイントはCANTALOUPE_S3SOURCE_ENDPOINTです。ここに、https://s3ds.mdx.jpを与えて、取得したACCESS_KEY_IDやSECRET_KEY、作成したBUCKET_NAMEやREGIONを設定します。 デモ 冒頭の記事でも使用した、いらすとやさんの画像を利用します。 https://www.irasutoya.com/2016/09/blog-post_810.html 以下、上記でアップロードした同じ画像ファイルを、Cantaloupeを使って配信している例です。 info.json https://cantaloupe.aws.ldas.jp/iiif/3/baby_asia_boy.png/info.json グレー化: full/max/0/gray.jpg https://cantaloupe.aws.ldas.jp/iiif/3/baby_asia_boy.png/full/max/0/gray.jpg なお、Cantaloupeを使って画像配信を行う場合には、上記の記事で実施したACLの設定(EveryoneにRead権限を与える)は不要です。デフォルトの設定を使用することで、オブジェクトストレージ上の画像ファイルへの直接アクセスは不可としつつ、Cantaloupeを介したアクセスのみを許可できるかと思います。 以下の記事で紹介したようなCantaloupe側のAccess Control設定を組み合わせることで、アクセス制御を実現することになるかと思います。 まとめ Amazon S3に格納した画像をIIIF画像として配信する方法として、以下の方法もあります。これが、Amazon S3以外のオブジェクトストレージにも対応しているのか、今後調査してみたいと思います。 IIIF画像の配信にあたり、参考になりましたら幸いです。

mdxのオブジェクトストレージを使用する(Cyberduckの利用)

mdxのオブジェクトストレージを使用する(Cyberduckの利用)

概要 mdxのオブジェクトストレージを使用する機会がありましたので、備忘録です。 https://mdx.jp/ 料金 2024年度の料金は以下のようになっています。 https://mdx.jp/guide/charge 1GBあたり、0.01ポイント(円)/日となっており、おおよそ1GBあたり、0.3円/月となっています。 申請方法 & s3cmdを用いた使い方 以下の公式チュートリアル動画が参考になりました。 https://www.youtube.com/watch?v=IN_4NS9hO2Y Cyberduckを使う 上記の動画ではコマンドラインツールによるファイル操作方法が紹介されています。 ここでは、Cyberduckを使用して、GUIを使ってファイル操作を行います。 AWS S3に対するCyberduckの操作方法を以下の記事で紹介しています。以下の方法を参考に、mdxのオブジェクトストレージに接続してみます。 接続設定 「新規接続」から接続設定を行います。 「Amazon S3」を選択して、サーバに「s3ds.mdx.jp」を入力します。 そして、発行された「アクセスキーID」および「シークレットアクセスキー」を入力します。 バケットの作成 右クリック > 「新規フォルダ」でバケットを作成できます。 ファイルのアップロード 以下のいらすとやさんの画像を使用します。 https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNuMuIaXnIW5QJXkLiV1ojUeUiIwNQF1O0lp2LgG2LGJUbIU8j4bFAyLyKq3BiYp53p0Yc8AtMsEykJAQgEx4SJyFvKY4OyNeDBFopPb4lnV7_wtZNkr91qwj6-m-8s-sl1aadYMhrpuoI/s800/baby_asia_boy.png 「satoru196」フォルダにドラッグ&ドロップでアップロードすることができます。 上述した公式チュートリアルでも言及されていますが、このままでは以下のURLにアクセスしても、表示ができません。 https://s3ds.mdx.jp/satoru196/baby_asia_boy.png 以下のようなエラーコードが表示されます。 <Error> <script/> <Code>AccessDenied</Code> <Message>Access Denied</Message> <RequestId>...</RequestId> <HostId>00000000000000000</HostId> </Error> ACLの変更 ファイルを右クリックして、「情報」をクリックします。 以下のように、Everyoneを選択して、 READ権限を付与します。 この結果、以下のURLから画像を閲覧することができます。 https://s3ds.mdx.jp/satoru196/baby_asia_boy.png まとめ mdxのオブジェクトストレージを活用することで、様々な用途がありますが、例えばメディアを安価に公開することができそうです。特に、デジタルアーカイブにおけるメディアの公開元として、有力なインフラになり得るかと思います。 mdxのs3互換のオブジェクトストレージの利用にあたり、参考になりましたら幸いです。

mdxでNDL古典籍OCRを実行する

mdxでNDL古典籍OCRを実行する

更新履歴 2024-05-22 「Dockerコマンドを実行するユーザーをdockerグループに追加」を追記しました。 概要 mdxは大学・研究機関で共創する産学官連携のためのデータプラットフォームです。 https://mdx.jp/ 今回は、mdxの仮想マシンを使用して、NDL古典籍OCRを実行してみます。 https://github.com/ndl-lab/ndlkotenocr_cli プロジェクトの申請 今回、プロジェクトタイプは「お試し/Trial」を選択しました。 「お試し/Trial」では、1つのGPUパックが割り当てられました。 仮想マシンの作成 デプロイ 今回は、「01_Ubuntu-2204-server-gpu (Recommended)」を選択しました。 デプロイ前の画面では、以下のように設定しました。パックタイプを「GPUパック」、パック数を1としました。 公開鍵については、ローカルPCで以下のように作成しました。 cd ~/.ssh/mdx ssh-keygen その後に作成されたid_rsa.pubの内容を貼り付けました。 その後、仮想マシンのデプロイが完了するまで少し待ちます。 SSH接続のためのネットワーク設定 以下の動画を参考に進めることができました。 https://youtu.be/p7OqcnXBQt8?si=E5JtC-xnrc5ZQYo_ まず起動した仮想マシンのサービスネットワーク1のIPv4アドレスを控えておきます。 次に、ネットワークタグから「DNAT」を追加しました。「転送元グローバルIPv4アドレス」は自動入力され、「転送先プライベートIPアドレス」に先ほど控えておいたサービスネットワークのIPv4アドレスを入力しました。 次に「ACL」を追加しました。動画にならって、以下のように設定しました。 特定のIPアドレスからのみアクセスする場合、以下のように設定しました。 一方、セキュリティの観点から、無制限に任意のアドレスからのアクセスを許可するのはリスクが伴いますが、以下のように設定することで、任意のアドレスからssh接続できるようです。 接続を試す DATで追加した転送元グローバルIPv4アドレスを使用します。初期ログイン後、パスワードの変更が求められるので、変更します。 ssh mdxuser@ -i ~/.ssh/mdx/id_rsa VS Codeで接続する その後の操作は、必須ではありませんが、VS Codeの拡張機能である「Remote Explorer」を使いました。 仮想マシン内での作業 GPUの確認 sudo su root@ubuntu-2204:/home/mdxuser# nvidia-smi +---------------------------------------------------------------------------------------+ | NVIDIA-SMI 535.86.10 Driver Version: 535.86.10 CUDA Version: 12.2 | |-----------------------------------------+----------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+======================+======================| | 0 NVIDIA A100-SXM4-40GB On | 00000000:03:00.0 Off | 0 | | N/A 25C P0 45W / 400W | 4MiB / 40960MiB | 0% Default | | | | Disabled | +-----------------------------------------+----------------------+----------------------+ +---------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=======================================================================================| | No running processes found | +---------------------------------------------------------------------------------------+ Dockerのインストール 以下のページの手順に沿って、Dockerをインストールしました。 ...