openai-assistants-quickstartの微修正

概要 OpenAIのAssistants APIを用いたRAG( Retrieval-augmented generation)を用いたチャット画面の構築にあたり、以下のリポジトリを使用しました。 https://github.com/openai/openai-assistants-quickstart この時、citationの扱いについて修正が必要であったため、備忘録としてメモします。 背景 上記のリポジトリを使い、OpenAIのAssistants APIを用いたRAGを試みました。 この時、デフォルトの設定では、以下のように、「4:13†」のように、引用箇所を示す記号がそのまま表示されてしまいました。 対策 annotateLastMessageを以下のように修正しました。file_pathをfile_citationに変更することで、引用箇所を置換することができた。 一例として、以下では、File APIへのリンクに置換しています。 const annotateLastMessage = (annotations) => { // Get the current messages setMessages((prevMessages) => { const lastMessage = prevMessages[prevMessages.length - 1]; const updatedLastMessage = { ...lastMessage, }; annotations.forEach((annotation) => { if (annotation.type === "file_citation") { updatedLastMessage.text = updatedLastMessage.text.replaceAll( annotation.text, `[リンク](/api/files/${annotation.file_citation.file_id})` ); } }); return [...prevMessages.slice(0, -1), updatedLastMessage]; }); }; 結果、以下のようにリンクが表示されました。 まとめ 目的に応じて、置換の内容を変更できるかと思います。参考になりましたら幸いです。

2024年11月28日 · 1 分 · Nakamura

NDL古典籍OCR-Lite(ndlkotenocr-lite)をMac OSで使用する

概要 2024年11月26日にNDLラボから、NDL古典籍OCR-Liteが公開されました。 https://lab.ndl.go.jp/news/2024/2024-11-26/ 本記事ではMac OSでの使用方法について紹介します。 使用方法(動画) https://www.youtube.com/watch?v=NYv93sJ6WLU 使用方法(テキスト) 以下にアクセスします。 https://github.com/ndl-lab/ndlkotenocr-lite/releases/tag/1.0.0 一覧からmacosを含むものを選びます。またチップについても、合致するものを選択します。 リンクをクリックすると、以下のように、「ndlkotenocr-lite_v1.0.0_macos_m1.tar.gz」がダウンロードされます。 ダブルクリック等で展開すると、macosというフォルダの中に、「NDLkotenOCR-Lite」というアプリケーションが展開されます。 「NDLkotenOCR-Lite」というアプリケーションをダブルクリックして起動します。 ただし、初回実行時は、以下のような警告と共に開くことができません。 「プライバシーとセキュリティ」に移動して、「このまま開く」を押すことで、アプリケーションを開くことができます。 結果、以下が起動します。 処理対象と出力先を選択して「OCR」ボタンを押すことで、以下のように認識されました。 ここでは『源氏物語』(東京大学総合図書館所蔵)を使用しています。 出力結果としては、txt, json, xmlファイルが生成されました。 まとめ 現時点ではNDL古典籍OCR ver.3と比較すると、読み取り精度が平均して約2%程度低下するとのことですが、GPUがなくとも軽量なOCR処理が可能となった点は大きなメリットだと思います。 開発者および公開に関わった方々に感謝いたします。

2024年11月27日 · 1 分 · Nakamura

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の利用にあたり、参考になりましたら幸いです。

2024年11月19日 · 1 分 · Nakamura

GakuNin RDMとfigshareを接続する

概要 GakuNin RDMとfigshareを接続する機会がありましたので、備忘録です。 figshareでの作業 GakuNin RDMとの連携対象のフォルダを作成します。 まずプロジェクトを作成します。以下では「My First Project」というプロジェクトを作成します。 GakuNin RDMとは、ここで作成したプロジェクト単位に連携ができるようでした。 GakuNin RDMでの設定 GakuNin RDM側で作成したプロジェクト(ここでは「My First Project」)を選択します。 GakuNin RDMでのアップロードと閲覧 接続設定を行った後は、他のストレージと同様に、フォルダの作成やファイルのアップロードができました。 注意点として、他のストレージサービスとは異なり、フォルダは1階層しか作成することはできませんでした。これはGakuNin RDM側の「フォルダ」の単位が、figshare側の「Item」という単位に対応するためと考えられます。 figshare側での閲覧 GakuNin RDM側で作成したフォルダは、figshare側では「Item」という単位で登録されました。 ファイルはその「Item」というデータセットの中の1ファイルとして、以下のように扱われるようでした。 参考 参考までに、figshare側でアイテムを作成する方法をメモします。 作成したプロジェクト内で「Item」を作成します。以下では「My First Folder」というアイテムを作成しています。 結果、以下のように、Project「My First Project」内に作成したアイテム「My First Folder」が作成されました。 まとめ GakuNin RDMとfigshareの連携にあたり、参考になりましたら幸いです。

2024年11月19日 · 1 分 · Nakamura

GakuNin RDMをNext.jsから使用する

概要 GakuNin RDMをNext.jsから使用する備忘録です。 背景 以下の記事で、NextAuth.jsを使って、GakuNin RDMの認証を行う方法を紹介しました。 この延長で、GakuNin RDMのデータをロードするNext.jsのアプリを試作します。 デモ GakuNin RDMの認証が使用できる方に限られますが、以下からお試しいただけます。 https://rdm-app.vercel.app/ 例えば以下は、接続したストレージの一覧を確認するページです。 選択したストレージ(ここではosfstorage)におけるフォルダやファイルの一覧です。 以下は、figshareに登録したファイルを参照している例です。 osfstorageやfigshare、GitHubなど、さまざまなストレージに格納されたデータを共通のAPIから利用できる点は便利だと感じました。 GitHubのリポジトリは以下です。 https://github.com/nakamura196/rdm_app まとめ 現時点(データをロードするだけ)においては、本アプリを使用する利点はありませんが、今後、他のアプリとの連携などを通じて、GakuNin RDMのデータを活用できればと思います。 参考になりましたら幸いです。

2024年11月19日 · 1 分 · Nakamura

GakuNin RDMのAPIを使って、ファイルのアップロードなどを行う

背景 GakuNin RDMのAPIを使って、ファイルのアップロードなどを行う方法の備忘録です。 参考 以下でPAT(パーソナルアクセストークン)の取得方法などを説明しています。 また以下では、OAuth (Open Authorization)を使った方法を紹介しています。Webアプリなどから使用される場合には、こちらが参考になりましたら幸いです。 方法 nbdevを使って、以下のリポジトリを作成しました。 https://github.com/nakamura196/grdm-tools 以下でドキュメントを確認できます。 https://nakamura196.github.io/grdm-tools/ プロバイダ(osfstorage)とフォルダのID(6735a92e6dc8e1001062ac08)は変更する必要がありますが、以下のようなスクリプトにより、特定のフォルダにファイルをアップロードできます。 from grdm_tools.api import GrdmClient import os client = GrdmClient( token=os.environ.get('GRDM_TOKEN') ) project_id = "ys86g" file_path = "./sample.png" url = f"https://files.rdm.nii.ac.jp/v1/resources/{project_id}/providers/osfstorage/6735a92e6dc8e1001062ac08/?kind=file" client.upload_file(file_path, url) ソースコードは以下からご確認いただけます。 https://nakamura196.github.io/grdm-tools/api.html#grdmclient.upload_file まとめ GakuNin RDMのAPI利用にあたり、参考になりましたら幸いです。

2024年11月16日 · 1 分 · Nakamura

NextAuth.jsを使って、ORCID・The Open Science Framework・ GakuNin RDMの認証を行う

概要 NextAuth.jsを使って、ORCID・OSF(The Open Science Framework)・ GRDM(GakuNin RDM)の認証を行う方法です。 デモアプリ ORCID https://orcid-app.vercel.app/ OSF https://osf-app.vercel.app/ GRDM https://rdm-app.vercel.app/ リポジトリ ORCID https://github.com/nakamura196/orcid_app 以下がオプションの記述例です。 https://github.com/nakamura196/orcid_app/blob/main/src/app/api/auth/[…nextauth]/authOptions.js export const authOptions = { providers: [ { id: "orcid", name: "ORCID", type: "oauth", clientId: process.env.ORCID_CLIENT_ID, clientSecret: process.env.ORCID_CLIENT_SECRET, authorization: { url: "https://orcid.org/oauth/authorize", params: { scope: "/authenticate", response_type: "code", redirect_uri: process.env.NEXTAUTH_URL + "/api/auth/callback/orcid", }, }, token: "https://orcid.org/oauth/token", userinfo: { url: "https://pub.orcid.org/v3.0/[ORCID]", async request({ tokens }) { const res = await fetch(`https://pub.orcid.org/v3.0/${tokens.orcid}`, { headers: { Authorization: `Bearer ${tokens.access_token}`, Accept: "application/json", }, }); return await res.json(); }, }, profile(profile) { return { id: profile["orcid-identifier"].path, // ORCID の ID を取得 name: profile.person?.name?.["given-names"]?.value + " " + profile.person?.name?.["family-name"]?.value, email: profile.person?.emails?.email?.[0]?.email, }; }, }, ], callbacks: { async session({ session, token }) { session.accessToken = token.accessToken; session.user.id = token.orcid; // ORCID ID をセッションに追加 return session; }, async jwt({ token, account }) { if (account) { token.accessToken = account.access_token; token.orcid = account.orcid; } return token; }, }, }; OSF https://github.com/nakamura196/osf-app ...

2024年11月15日 · 3 分 · Nakamura

OldMaps Onlineを使ってみる

概要 OldMaps Onlineを使用する機会がありましたので、備忘録です。 https://www.oldmapsonline.org/ 登録 Googleアカウント等でログインします。無料アカウントでは1つのプライベート画像を登録できました。 今回は、「東京帝國大學本部構内及農學部建物鳥瞰圖(東京大学農学生命科学研究科・農学部)」を対象にします。 https://da.dl.itc.u-tokyo.ac.jp/portal/assets/187cc82d-11e6-9912-9dd4-b4cca9b10970 以下のマニフェストファイルを使って画像を登録します。 https://iiif.dl.itc.u-tokyo.ac.jp/repo/iiif/187cc82d-11e6-9912-9dd4-b4cca9b10970/manifest その後、メタデータを登録する画像が表示されました。 メニュー 以下に示すように、「This map」「Georeference」「Transcribe」「Compare」の機能が提供されています。「This map」は上述のページに遷移します。 以下、その他の機能について確認します。 Georeference ジオリファレンスを行う機能です。 Side by sideによる表示や、 Overlayによる表示機能がありました。 今回は、35点をポイントしてみました。 Transcribe 翻刻機能も提供されていました。以下のように画像の一部を選択し、そのテキストを入力することができます。 Compare ジオリファレンスした結果を閲覧する機能です。 Gridによる表示や、 Swipeによる表示、 Spy glassによる表示など、さまざまなインタフェースが提供されていました。 結果 今回作成した地図は以下からご確認いただけます。 https://www.oldmapsonline.org/compare#map/5523c467-3744-4099-a6fe-61fc63c2ee9d まとめ 古地図の活用にあたり、参考になりましたら幸いです。

2024年11月12日 · 1 分 · Nakamura

Knight LabのTimelineJSやStoryMapJSをNext.jsから利用する

概要 Knight LabのTimelineJSやStoryMapJSをNext.jsから利用する方法のメモです。 背景 Knight LabのTimelineJSやStoryMapJSは、デジタルストーリーテリングのためのオープンソースツールです。 https://knightlab.northwestern.edu/ データ 以下で公開されている『渋沢栄一伝記資料』のテキストデータを利用します。 https://github.com/shibusawa-dlab/lab1 リポジトリ 以下で公開しています。 https://github.com/nakamura196/shibusawa ストーリーマップ 以下のようなコンポーネントを用意することで、Next.jsからも利用することができました。 https://github.com/nakamura196/shibusawa/blob/main/src/components/Storymap.tsx TypeScriptの利用にあたり、以下の型定義ファイルも作成しました。 https://github.com/nakamura196/shibusawa/blob/main/src/global.d.ts 以下のように表示することができました。 https://shibusawa.vercel.app/storymap/1868-08-02 タイムライン ストーリーマップ同様、タイムラインについても以下のようなコンポーネントを作成しました。 https://github.com/nakamura196/shibusawa/blob/main/src/components/Timeline.tsx 以下のように表示することができました。 https://shibusawa.vercel.app/timeline/1868 ただし、タイムラインについては、以下でES6 modules/webpackが公開されていることに後から気がつきました。こちらの使い方について、別途調査したいと思います。 https://www.npmjs.com/package/@knight-lab/timelinejs まとめ デジタル・ヒューマニティーズ(DH)の分野で広く活用されているTimelineJSやStoryMapJSについて、データの視覚化や物語の構築を行う際の参考になりましたら幸いです。 なお、これらのツールはプログラムを介さず、Googleスプレッドシートを入力として、可視化アプリを作成することもできます。こちらも参考になりましたら幸いです。 https://timeline.knightlab.com/ https://storymap.knightlab.com/

2024年11月7日 · 1 分 · Nakamura

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 ...

2024年11月6日 · 1 分 · Nakamura

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画像のデータセットが作成されました。 ...

2024年11月6日 · 4 分 · Nakamura

Omeka Sの特定のvocabularyのプロパティ一覧を取得する

概要 Omeka Sの特定のvocabularyのプロパティ一覧を取得する方法です。 方法 以下を対象にします。 https://uta.u-tokyo.ac.jp/uta/api/properties?vocabulary_id=5 次のプログラムにより、プロパティ一覧をMS Excelに書き込みます。 import pandas as pd import requests url = "https://uta.u-tokyo.ac.jp/uta/api/properties?vocabulary_id=5" page = 1 data_list = [] while 1: response = requests.get(url + "&page=" + str(page)) data = response.json() if len(data) == 0: break data_list.extend(data) page += 1 remove_keys = ["@context", "@id", "@type", "o:vocabulary", "o:id", "o:local_name"] for data in data_list: for key in remove_keys: if key in data: del data[key] # DataFrameに変換 df = pd.DataFrame(data_list) df.to_excel("archiveshub.xlsx", index=False) 結果 以下のようなMS Excelが得られます。 o:label o:comment o:term Maintenance Agency A repository responsible for the maintenance of the archival finding aid. archiveshub:maintenanceAgency Is Maintenance Agency Of An archival finding aid for which the repository is responsible for the maintenance. archiveshub:isMaintenanceAgencyOf Encoded As An EAD document that is an encoding of the archival finding aid. archiveshub:encodedAs Encoding Of An archival finding aid of which the EAD document is an encoding. archiveshub:encodingOf Administers A resource which the agent manages. archiveshub:administers Is Administered By An agent that manages the resource. archiveshub:isAdministeredBy Provides Access To A resource to which the agent provides access. archiveshub:providesAccessTo Access Provided By An agent that provides access to the resource. archiveshub:accessProvidedBy Is Publisher Of A resource which the agent makes available. archiveshub:isPublisherOf Level An indicator of the part of an archival collection constituted by an archival resource. archiveshub:level Is Represented By A resource which represents the archival resource, such as an image of a text page, a transcription of text, an audio or video clip, or an aggregation of such resources. archiveshub:isRepresentedBy Origination An agent responsible for the creation or accumulation of the archival resource. archiveshub:origination Is Origination Of An archival resource for which the agent is responsible for the creation or accumulation. archiveshub:isOriginationOf Has Biographical History A narrative or chronology that places archival materials in context by providing information about their creator(s). archiveshub:hasBiographicalHistory Is Biographical History For An archival resource that the narrative or chronology places in context by providing information about their creator(s). archiveshub:isBiographicalHistoryFor Associated With A concept adjudged by a cataloguer to have an association with an archival resource which they consider useful for the purposes of discovering that resource. archiveshub:associatedWith Members Members archiveshub:members Country Code The ISO 3166-1 code for the country of the repository. archiveshub:countryCode Maintenance Agency Code The ISO 15511 code for the repository. archiveshub:maintenanceAgencyCode Body A literal representation of the content of the document. archiveshub:body Date created or accumulated The date, represented as a string, of a time interval during which the archival resource was created or accumulated. archiveshub:dateCreatedAccumulatedString Date created or accumulated The date, represented as a typed literal, of a time interval during which the archival resource was created or accumulated. archiveshub:dateCreatedAccumulated Date created or accumulated (start) The start date, represented as a typed literal, of a time interval during which the archival resource was created or accumulated. archiveshub:dateCreatedAccumulatedStart Date created or accumulated (end) The end date, represented as a typed literal, of a time interval during which the archival resource was created or accumulated. archiveshub:dateCreatedAccumulatedEnd Date of Birth The date of birth of the person. archiveshub:dateBirth Date of Death The date of death of the person. archiveshub:dateDeath Extent The size of the archival resource. archiveshub:extent Custodial History Custodial History archiveshub:custodialHistory Acquisitions Acquisitions archiveshub:acquisitions Scope and Content Scope and Content archiveshub:scopecontent Appraisal Appraisal archiveshub:appraisal Accruals Accruals archiveshub:accruals Access Restrictions Access Restrictions archiveshub:accessRestrictions Use Restrictions Use Restrictions archiveshub:useRestrictions Physical and Technical Requirements Physical and Technical Requirements archiveshub:physicalTechnicalRequirements Other Finding Aids Other Finding Aids archiveshub:otherFindingAids Location of Originals Location of Originals archiveshub:locationOfOriginals Alternate Forms Available Alternate Forms Available archiveshub:alternateFormsAvailable Related Material Related Material archiveshub:relatedMaterial Bibliography Bibliography archiveshub:bibliography Note Note archiveshub:note Processing Processing archiveshub:processing Name Name archiveshub:name Dates Dates archiveshub:dates Location Location archiveshub:location Other Other archiveshub:other Surname The surname of a person who is the focus of the concept archiveshub:surname Forename The forename of a person who is the focus of the concept archiveshub:forename Title The title of a person who is the focus of the concept archiveshub:title Epithet Epithet archiveshub:epithet Archival Box A number of archival boxes archiveshub:archbox Metre A number of metres archiveshub:metre Cubic Metre A number of cubic metres archiveshub:cubicmetre Folder A number of folders archiveshub:folder Envelope A number of envelopes archiveshub:envelope Volume A number of volumes archiveshub:volume File A number of files archiveshub:file Item A number of items archiveshub:item Page A number of pages archiveshub:page Paper A number of papers archiveshub:paper まとめ Omeka Sの利用にあたり、参考になりましたら幸いです。 ...

2024年11月5日 · 4 分 · Nakamura

Omeka SのCustom Vocabモジュールを使って、他のアイテムを関連づける

概要 Omeka SのCustom Vocabモジュールを使って、他のアイテムを関連づける機会がありましたので、備忘録です。 背景 以下の記事で、カスタム語彙の使い方を説明しました。 今回は、文字列やURIsでなく、アイテムを関連づけてみます。 アイテムセットの作成 まず、関連付け対象とするアイテムを格納するアイテムセットを作成します。 今回は、「二次利用条件表示」というアイテムセットを作成します。 「二次利用条件表示」に関するアイテムの作成 以下のように、アイテムを作成しました。 ここのアイテムは、以下のように、タイトルや内容記述、識別子などを与えます。 カスタム語彙の作成 以下のように、カスタム語彙を作成します。ポイントとして、Vocab typeにおいて「アイテム」を選択し、アイテムにおいて、前のステップで作成したアイテムセット「二次利用条件表示」を選択します。 リソーステンプレートの作成 リソーステンプレートを作成して、データタイプにおいて、作成したカスタム語彙を選択します。 任意のアイテムの作成 任意のアイテムの作成において、先に作成したリソーステンプレートを選択します。結果、以下のように、設定したアイテムセットのアイテムから値を選択するようになります。 利点 今回説明したような方法を採用することで、指定した項目から値を選択する形式になり、表記揺れを防ぐことができます。また、その値をアイテムとして設定することで、メタデータの管理を一元化することが可能です。例えば、二次利用条件表示の内容を更新したい場合は、該当する二次利用条件表示のメタデータのみを更新すればよく、関連付けた複数のアイテムを個別に更新する必要はありません。 これは、Drupalにおけるタクソノミーのような使い方に該当します。 まとめ Omeka Sの利用にあたり、参考になりましたら幸いです。

2024年11月4日 · 1 分 · Nakamura

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弱かかってしまいました。 ...

2024年11月4日 · 1 分 · Nakamura

XSLTを使ってIIIFとTEIの対照表示を実現する

概要 XSLTを使ってIIIFとTEIの対照表示を実現してみる機会がありましたので、備忘録です。 結果は以下からご確認いただけます。「校異源氏物語テキストDB」を利用しています。 https://kouigenjimonogatari.github.io/xml/xsl/01.xml 背景 TEI/XMLの可視化にあたって、これまでは、TEI XMLをHTMLに変換してブラウザ上で表示するためのJavaScriptライブラリであるCETEICeanを使うことが多かったです。 これらの取り組みではJavaScriptのフレームワークと合わせて、柔軟な開発が可能でした。 しかし、この方法ではTEI/XMLとは別に、ビューアのデプロイが必要であるなど、課題を感じる点もありました。 対策 そこで、XSLTを使ったIIIFとTEIの対照表示に取り組みました。以下のXSLファイルを用意しました。実装にあたっては、ChatGPTを利用しました。 https://github.com/kouigenjimonogatari/kouigenjimonogatari.github.io/blob/master/xsl/mirador.xsl そして、XMLファイルからは、以下のように参照します。相対パスとなっている点は、適宜読み替えてください。 <?xml version="1.0" ?> ... <?xml-stylesheet type="text/xsl" href="../../xsl/mirador.xsl"?> <TEI xmlns="http://www.tei-c.org/ns/1.0"> <teiHeader> <fileDesc> <titleStmt> <title>校異源氏物語・きりつぼ</title> <author>池田亀鑑</author> ... これにより、以下のようなXMLファイルをブラウザで表示すると、 https://kouigenjimonogatari.github.io/xml/xsl/01.xml 以下のように、IIIFとTEIの対照表示を実現することができました。ページのリンクやMiradorビューアの前後ボタンのクリックにより、テキストと画像が同期します。 このようにXSLTによる可視化を行うことにより、別途のビューア開発やデプロイが不要となり、またxslファイルの更新による容易なカスタマイズを実現することができました。 考察 Next.jsのようなフレームワークとCETEIceanを組み合わせてビューアを作成する方法と、本記事で紹介したようなXSLTを使った可視化方法について、ChatGPTに使い分けを聞いてみました。 結果、以下のように、比較的単純な可視化ではXSLT、高度なインタクラションが求められる場合はCETEIcean、を選択するのがよさそうでした。 1. 高度なインタラクションが必要な場合: Next.js + CETEIcean Next.js はReactベースのフレームワークで、クライアントサイドレンダリングやサーバーサイドレンダリング、APIの統合などを柔軟に行えます。Next.jsを使うと、複雑なUIや状態管理、ナビゲーション、動的なデータ処理が必要なアプリケーションの構築が簡単です。 CETEIcean は、TEI XMLをそのままHTMLにレンダリングするためのライブラリで、特にクライアントサイドでTEIを動的に表示したい場合に便利です。CETEIceanを使うと、JavaScriptを使ってTEI要素を直接操作できるため、ユーザーがクリックした際に特定のページに遷移したり、アノテーションの追加など、インタラクティブな機能を実装できます。 利点 : リッチなインタラクション(ページナビゲーション、フィルタリング、ユーザーの操作に応じた動的なUIの更新など)が容易。 コンポーネントベースの設計が可能で、保守性が高く再利用性も高い。 さまざまなJavaScriptライブラリやプラグイン(Mirador、Annotoriousなど)との統合が容易。 2. 単純な表示や静的な構造でよい場合: XSLT XSLT は、XMLデータをHTMLなどに変換するためのテンプレート言語で、サーバーサイドまたはクライアントサイドでの静的な表示に適しています。XSLTを使用すると、TEI XMLをシンプルなHTMLとして表示できます。 利点 : 軽量で設定がシンプル。ブラウザがXSLTをサポートしていれば、特別な環境を必要とせずに、直接HTML表示が可能。 HTMLとして生成されるため、CSSによるスタイルの適用が容易で、簡単なナビゲーションや静的なページリンク程度なら実装も比較的簡単。 静的なレポートや閲覧専用のデータの表示に最適。 判断基準のまとめ 高度な機能やインタラクティブな要素が求められる :Next.js + CETEIcean 例:クリックやスクロールに応じて動的にデータをロード、複数のナビゲーションや検索機能の提供、アノテーションや画像ビューワーの統合。 単純な表示がメイン :XSLT 例:TEIドキュメントをただ表示するだけ、特定の要素にスタイルを適用して閲覧しやすくする、シンプルなページナビゲーション。 まとめ ビューアを使用せずに、TEI/XMLファイルとXSLファイルのみで閲覧環境を実現することは、管理や運用コストの低減にもつながるように思いました。 ...

2024年11月2日 · 1 分 · Nakamura

Google Cloud Vision APIを用いて、単一ページから構成される透明テキスト付きPDFを作成する

概要 PDFを対象に、Google Cloud Vision APIを使って、透明テキスト付きPDFを作成する機会がありましたので、備忘録です。 以下、simpleで検索した例です。 背景 今回は単一ページから構成されるPDFを対象とします。 手順 画像の作成 OCRの対象とする画像を作成します。 デフォルトの設定だとボヤけた画像ができてしまったので、解像度を2倍に設定し、また後述するプロセスで、解像度を考慮した位置合わせを実施しています。 以下をインストールします。 PyMuPDF Pillow import fitz # PyMuPDF from PIL import Image import json from tqdm import tqdm import io # 入力PDFファイルと出力PDFファイル input_pdf_path = "./input.pdf" # 単一ページのPDFファイル output_pdf_path = "./output.pdf" # 入力PDFファイルを開き、単一ページを読み込み pdf_document = fitz.open(input_pdf_path) page = pdf_document[0] # 最初のページを選択 # ページを画像としてレンダリングし、OCRでテキストを抽出 # pix = page.get_pixmap() # 解像度300 DPIでレンダリング zoom = 2.0 # 解像度を上げるためにズーム設定 mat = fitz.Matrix(zoom, zoom) pix = page.get_pixmap(matrix=mat) img = Image.open(io.BytesIO(pix.tobytes("png"))) img.save("./image.png") Google Cloud Vision API 出力された画像を対象に、Google Cloud Vision APIを適用します。 { "textAnnotations": [ { "boundingPoly": { "vertices": [ { "x": 141, "y": 152 }, { "x": 1082, "y": 152 }, { "x": 1082, "y": 1410 }, { "x": 141, "y": 1410 } ] }, "description": "Sample PDF...", "locale": "la" }, { "boundingPoly": { "vertices": [ { "x": 141, "y": 159 }, { "x": 363, "y": 156 }, { "x": 364, "y": 216 }, { "x": 142, "y": 219 } ] }, "description": "Sample" }, { "boundingPoly": { "vertices": [ { "x": 382, "y": 156 }, { "x": 506, "y": 154 }, { "x": 507, "y": 213 }, { "x": 383, "y": 215 } ] }, "description": "PDF" }, ... 出力結果として得られるJSONファイルを./google_ocr.jsonといった名前で保存します。 ...

2024年11月2日 · 2 分 · Nakamura

ZoteroのAPIをNext.jsから使う

概要 ZoteroのAPIをNext.jsから使う方法を調べましたので、備忘録です。結果、以下のアプリケーションを作成しました。 https://zotero-rouge.vercel.app/ ライブラリ 以下のライブラリを使用しました。 https://github.com/tnajdek/zotero-api-client API Keyなどの取得 以下の記事を参考にしてください。 使い方 コレクション一覧 // app/api/zotero/collections/route.js import { NextResponse } from "next/server"; import api from "zotero-api-client"; import { prisma } from "@/lib/prisma"; import { decrypt } from "../../posts/encryption"; import { getSession } from "@auth0/nextjs-auth0"; async function fetchZoteroCollections( zoteroApiKey: string, zoteroUserId: string ) { const myapi = api(zoteroApiKey).library("user", zoteroUserId); const collectionsResponse = await myapi.collections().get(); return collectionsResponse.raw; } 特定のコレクション // app/api/zotero/collection/[id]/route.ts import { NextResponse } from "next/server"; import api from "zotero-api-client"; import { prisma } from "@/lib/prisma"; import { decrypt } from "@/app/api/posts/encryption"; import { getSession } from "@auth0/nextjs-auth0"; async function fetchZoteroCollection( zoteroApiKey: string, zoteroUserId: string, collectionId: string ) { const myapi = api(zoteroApiKey).library("user", zoteroUserId); const collectionResponse = await myapi.collections(collectionId).get(); return collectionResponse.raw; } 特定のコレクション内のアイテム一覧 // app/api/zotero/collection/[id]/items/route.ts import { NextResponse, NextRequest } from "next/server"; import api from "zotero-api-client"; import { prisma } from "@/lib/prisma"; import { decrypt } from "@/app/api/posts/encryption"; import { getSession } from "@auth0/nextjs-auth0"; async function fetchZoteroCollection( zoteroApiKey: string, zoteroUserId: string, collectionId: string ) { const myapi = api(zoteroApiKey).library("user", zoteroUserId); const collectionResponse = await myapi .collections(collectionId) .items() .get(); return collectionResponse.raw; 参考 アプリケーションはVercelにホスティングされており、データベースにはVercel Postgres、ORMにはPrismaを使用しました。UIはTailwind CSSで構築され、ChatGPTのデザイン提案を使用しました。また、認証にはAuth0を採用しています。 まとめ ZoteroのAPI利用にあたり、参考になりましたら幸いです。 ...

2024年11月1日 · 1 分 · Nakamura

LEAF WriterのEditor Toolbarをカスタマイズする

概要 LEAF Writerでは、画面上部にタグの挿入をサポートするボタンが提供されています。本記事では、その編集方法について紹介します。 結果、以下のように、<app><lem>あああ</lem><rdg>いいい</rdg></app>を挿入する機能を追加しました。 https://youtu.be/XMnRP7s2atw 編集 以下のファイルを編集します。 packages/cwrc-leafwriter/src/components/editorToolbar/index.tsx 以下のように、人名や地名のタグをサポートする機能が設定されています。例えば、以下では、organizationに関する記述をコメントアウトしています。 ... const items: (MenuItem | Item)[] = [ { group: 'action', hide: isReadonly, icon: 'insertTag', onClick: () => { if (!container.current) return; const rect = container.current.getBoundingClientRect(); const posX = rect.left; const posY = rect.top + 34; showContextMenu({ // anchorEl: container.current, eventSource: 'ribbon', position: { posX, posY }, useSelection: true, }); }, title: 'Tag', tooltip: 'Add Tag', type: 'button', }, { group: 'action', type: 'divider', hide: isReadonly }, { color: entity.person.color.main, group: 'action', disabled: !isSupported('person'), hide: isReadonly, icon: entity.person.icon, onClick: () => window.writer.tagger.addEntityDialog('person'), title: 'Tag Person', type: 'iconButton', }, { color: entity.place.color.main, group: 'action', disabled: !isSupported('place'), hide: isReadonly, icon: entity.place.icon, onClick: () => window.writer.tagger.addEntityDialog('place'), title: 'Tag Place', type: 'iconButton', }, /* { color: entity.organization.color.main, group: 'action', disabled: !isSupported('organization'), hide: isReadonly, icon: entity.organization.icon, onClick: () => window.writer.tagger.addEntityDialog('organization'), title: 'Tag Organization', type: 'iconButton', }, ... 結果、以下のように選択肢が限定されます。 ...

2024年10月31日 · 4 分 · Nakamura

ArchivematicaのMETSファイルの内容を可視化するPythonライブラリ

概要 ArchivematicaのMETSファイルの内容を可視化するPythonライブラリを作成しました。 例えば以下のように、AIPの作成過程で行われた処理(premis:event)の集計結果などを可視化します。 背景 以下の記事で、ArchivematicaのMETSファイルを人間に優しい方法で探索するためのウェブアプリケーションであるMETSFlaskを紹介しました。 今回作成したものは、このMETSFlaskで提供されている機能を、Flask以外からも利用しやすいようにライブラリ化したものです。 リポジトリ 以下で公開しています。README.mdファイルに使用方法を記載しています。 https://github.com/nakamura196/mets_tools GitHub Pagesでもドキュメントを公開しています。 https://nakamura196.github.io/mets_tools/ まとめ ArchivematicaおよびAIPの利用にあたり、参考になりましたら幸いです。

2024年10月31日 · 1 分 · Nakamura

LEAF WriterをNext.jsから使用する

概要 LEAF WriterをNext.jsから使用する方法について紹介します。 デモ 以下のURLからお試しいただけます。 https://leaf-writer-nextjs.vercel.app/ 以下が画面例です。ヘッダー部分がNext.jsを用いて追加した部分です。エディタ部分はLEAF Writerを使用しています。 ソースコードは以下でご確認いただけます。 https://github.com/nakamura196/leaf-writer-nextjs 使用方法 以下に記載があります。 https://gitlab.com/calincs/cwrc/leaf-writer/leaf-writer/-/tree/main/packages/cwrc-leafwriter?ref_type=heads 注意点として、div containerのidをleaf-writer-containerにする必要があります。これを行わない場合、スタイルが崩れることがわかりました。この点は、今後プルリクエストを送りたいと思います。 # const container = document.getElementById('#leaf-writer'); const container = document.getElementById('#leaf-writer-container'); まとめ LEAF Writerの応用にあたり、参考になりましたら幸いです。

2024年10月29日 · 1 分 · Nakamura