ラベル アプリケーション の投稿を表示しています。 すべての投稿を表示
ラベル アプリケーション の投稿を表示しています。 すべての投稿を表示

2026年6月6日土曜日

MediaWiki(6)

MediaWiki(5)からの続き


図:Fisica Wiki の現在のトップページ


毎日,MediaWikiに手を入れている。ChatGPTがどういう手順で作業すればよいかを提案してくれたので,それに従って作業してきた。次のようなことである。
1. 物理学者記事移植の開始
2. Special:Export / Special:Import の注意点
3. Commons / Wikiquote 系ボックスの文字はみ出し対策
4. Normdaten / Authority control の縮退
5. WikidataCheck エラーへの対応
6. 国旗テンプレートの簡易整備
7. Infobox Scientist の安定化
8. 画像表示と InstantCommons
9. 不要な管理テンプレートの扱い
10. 第2段階:20名基準セットの作成
組込み用の軽量スクリプト言語のLuaが,MediaWikiにも使われている。それが引っかかるエラーが大きかったのだが,うまく回避する方法が提案された。その結果,詳細は別にして,日本語Wikipedia からの移植がほぼほぼできるようになった。

その後,国旗のsvgファイルを表示させる過程で問い詰めたら,なんと,LocalSettings.php に  \$wgUseInstantCommons = true; を設定すれば,オリジナルのウィキメディア・コモンズの画像データを直接引っ張ってこれることがわかった。肖像写真などもOKだ。早く言ってほしい。

というわけで,さくらインターネット上のMediaWiki(Fisica Wiki)の環境設定は一段落することになった。コンテンツはこれからゆっくり料理することにしよう。物理分野のカテゴリどうする問題はあるけれど,仮の住まいだと思ってがまんすることに。

2026年6月5日金曜日

MediaWiki(5)

MediaWiki(4)からの続き

自分自身の情報整理能力がどんどん衰えているため,いきおい他人(AI)に頼ることになってしまうが,まあしょうがないか。これで戦争にでもなって,生成AIへのアクセスを止められた日には,とんでもないことになる。そのときはGoogle検索もMicrosoft Officeも使えないかもなので,いずれにせよ日本の全機能が停止するのかもしれない。あるいは,OSごと動かなくなくなるとか。残るのはLinuxなどのFree Softwareのみ


Q(koshix): 
Fisica Wiki の件ですが,構造が複雑で,なにがどこにはいっているのか。
・最初から構造として組み込まれているもの
・自分が移植したテンプレートやモジュール等
・自分が作った(移植した)コンテンツやメディア
 がどうなっていて,それぞれどうやって探せばいいのかを なるべく初心者向けに分かりやすく解説してください。

A(ChatGPT):
(回答略)

Q(koshix):
回答が冗長で回りくどいので,要点をもれなく簡潔に整理してください。

A(Gemini):
Fisica Wikiの構造と探し方を、3つのカテゴリーに絞って簡潔に整理た。

1.構造の三層整理
Wikiは「器」「部品」「中身」の3階層でできている。
カテゴリー | 内容 | 実体(名前空間)
① 本体(器)|システムが最初から持っている機能   |特別ページ、サイドバー、検索欄
② 移植部品 |Wikipediaから持ってきた表示の仕組み |テンプレート:、モジュール:、MediaWiki:Common.css
③ コンテンツ|あなたが書いた記事やアップロード画像|(接頭辞なし)、Fisica Wiki:、ファイル:

2.目的別・探し方の最短ルート
「どこにあるか」を知るための5つの手段。
・全ページを棚卸ししたい
特別:全ページ を使う。上のプルダウンで「名前空間」を切り替えると、種類ごとに一覧が出る。
・最近の作業を確認したい
特別:最近の更新 を見る。自分が直近で触ったページが時系列で並ぶ。
・画像を確認したい
特別:ファイル一覧 を見る。ロゴや写真などのメディアだけが並ぶ。
・ページが何で構成されているか知りたい
そのページの「編集」画面を開く。{{...}} なら テンプレート、[[ファイル:...]] なら 画像。
・その部品がどこで使われているか知りたい
左メニューの リンク元 をクリック。そのテンプレートや画像を使っている記事が逆引きできる。

3.迷ったときの早見表
「あれはどこ?」となったら、ページ名の先頭(接頭辞)を確認。

探したいもの  | ページ名の例       | 探し方
物理学者の記事  |アルベルト・アインシュタイン |接頭辞なし(標準)
自分の作業メモ  |Fisica Wiki:物理学者記事移植  |Fisica Wiki: 名前空間
表示のひな形   |テンプレート:Cite web     |テンプレート: 名前空間
複雑な計算・処理 |モジュール:Citation/CS1   |モジュール: 名前空間
画像・ロゴ    |ファイル:fisica-logo.png   |ファイル: 名前空間
全体のデザイン調整|MediaWiki:Common.css   |直接ページ名を検索
アドバイス

混乱を防ぐため、「Fisica Wiki:物理学者記事移植」 のページに、よく使うテンプレートやCSSへのリンクを 「お気に入りリスト」 としてまとめておくと、名前空間を意識せずに一発でアクセスできるようになる。

2026年6月2日火曜日

MediaWiki(2)

MediaWiki(1)からの続き

図:Fisica_Wiki トップページ

さくらインターネットサーバーに,MediaWikiのページを立ち上げることができた。次に,日本語Wikipediaとできるだけ似たような見かけや機能にすることを目指している。このためには,Wikipediaから,テンプレートやモジュールをxmlファイルとしてダウンロードし,MediaWiki側に移植することが必要になる。
Wikipedia 特別:データ書き出し
https://ja.wikipedia.org/wiki/特別:データ書き出し
MediaWiki 特別:データ取り込み
https://nucleus.sakura.ne.jp/wiki/index.php/特別:データ取り込み
ChatGPTに相談したところ,次の5つのグループで進めてはどうかということだった。
第1グループ:脚注・出典の基本 ✓
テンプレート:Reflist,テンプレート:Cite web,テンプレート:Cite book,テンプレート:Cite journal
第2グループ:追加の出典テンプレート(×失敗)
テンプレート:Cite news,テンプレート:Cite press release,テンプレート:Cite conference,テンプレート:Citation
第3グループ:言語表記 ✓
テンプレート:Lang,テンプレート:En,テンプレート:De,テンプレート:Fr,テンプレート:La,テンプレート:仮リンク
第4グループ:関連項目・導線
テンプレート:Main,テンプレート:See also,テンプレート:See,テンプレート:For,テンプレート:Further
第5グループ:軽い整形補助
テンプレート:Nowrap,テンプレート:Smaller,テンプレート:Resize,テンプレート:Clear,テンプレート:Plainlist,テンプレート:Flatlist,テンプレート:Unbulleted list,テンプレート:Br separated entries

2026年6月1日月曜日

MediaWiki(1)



図:MediaWikiで始めて作ったウェブページ

メディアウィキMediaWiki)は,プログラミング言語PHPとMySQLなどのデータベースから構成されるウィキソフトウェアである。ウィキペディアやその関連プロジェクトはこのによって作成されている。昔は向日葵のアイコンでなじみ深かったが,いまはちょっとイマイチになった。

マニュアルレス時代が到来しているので,ほとんどの設定方法などは生成AIに聞いてみることで事足りる。今回は,Geminiの指導を仰いだ。ChatGPTの回答がいまいちだったからだ。
Q(koshix):
sakura internet のアカウント( サービス名 :さくらのレンタルサーバ スタンダード)で 公開用のMediaWiki(Wikipediaとほぼ同水準の)を立ち上げることはできますか。もし可能ならば,どの程度の工数が必要でしょうか。 

の最初の段階について ChatGPTにきいたところ以下の回答が得られました。 でも,ちょっと自分にとっては分かりにくくて不親切に思えるので,初心者向けに 丁寧かつ簡潔に修正していただけませんか。(以下ChatGPTの回答を添付)

(1) スタンダード契約しているさくらインターネットのコントロールパネルで,MySQLデータベースを新しく作成する。

(2) さくらインターネットのサーバーのウェブ公開ディレクトリ配下にwikiというディレクトリをつくる。MediaWikiのダウンロードサイトから入手したファイル(MediaWiki 1.45.3 安定版)を展開して,その中身をwikiに置く。

(3) httpでwikiディレクトリにアクセスし,初期化プロセスindex.phpを実行する。タイトルは,安易にPhys_Wikiとしたところ,田原真人のフィズヨビのなかでPhys-Wikiというコーナーが作られていたので,後にFisica_Wikiに変更した。 Wikiではあるけれども,管理者の自分だけが編集可能に設定する。外装はWikipediaになるべく近くなるようVector を指定する。

(4) 先ほど設定していたMySQLデータベースとの接続などを定義すると,LocalSettings.phpという設定ファイルができあがる。 これを自分のMacBook Airにダウンロードして,サーバーのwikiディレクトリに置く。CC-BY-SAも必須だ。これで準備は出来上がり。

(5) logoがデフォルトのままで美しくないので,Geminiと相談してそれっぽいデザインのものを作り,さらにそれをsvgに変換してもらう。そのまま埋め込んだらサイズが固定ではみ出てしまったので,そこも調整してもらう。なんでもかんでも任せっきりだ。

(6) バックアップの設定をしておけとの助言があった。少し問い合わせて指示に従って,さくらインターネットのコントロールパネルのWebサイト/バックアップ&ステージングでSnapUpを設定し,wikiのページのバックアップを指定したつもり(大丈夫かな?)。

(7) なるべく負荷少なく数式を表示したいので,ユーザ側でレンダリングするMathJaxを設定ファイルにCommon.jsに書く。いったんWAF設定のセキュリティ解除する必要があるとか,キャッシュのせいだとか,ななかなうまく反映できなかったが,最終的にはなんとかなった。

(注)昔は馬力があったので,あれこれ全部マニュアルと首っ引きで設定できた。その後は,インターネットで検索しながらになり,ついに生成AI(LLM)様に完全依存の状態に到達した。

/* MathJax 3 強制ロード・スクリプト */
mw.loader.using('mediawiki.util').done(function () {
    window.MathJax = {
        tex: {
            inlineMath: [['$', '$'], ['\\(', '\\)']],
            displayMath: [['$$', '$$'], ['\\[', '\\]']],
            processEscapes: true
        }
    };

    var script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
    script.async = true;
    document.head.appendChild(script);
    
    // ページ読み込み後に再レンダリングを命令
    script.onload = function() {
        if (window.MathJax && MathJax.typeset) {
            MathJax.typeset();
        }
    };
});




2026年4月22日水曜日

デジタルアドレス



以前,日経朝刊三面に日本郵便のデジタルアドレスの記事があった。企業向けに発行するというもので,個人向けは去年の5月から始まっている。早速試してみよう。

デジタルアドレスとは,日本郵政グループのゆうIDを持つ利用者に対して,その住所を表現する7桁の英数字記号を付与するというものだ。ゆうIDでは,郵便局アプリやかんぽアプリが利用でき,ゆうパックなどが便利になるらしい。一般利用者にはあまりメリットがわからないが,事業者はデジタルアドレスから住所への変換APIが使えるようになるので,間違いやすくて面倒な住所管理が7桁の英数字で完結することになる。

単純に考えると,(26+10)^7 = 783億通りのパターンがあり得る。一方,Geminiに聞いてみると,Iと1,Oと0は紛らわしいので,これらを除いた32文字で,7桁のうち1桁はチェックでジットに使うとおっしゃる。(26+10-4)^6 =10.7億通りのパターンになる。少なくないか。いちおう1人1ゆうID=1デジタルアドレスで,引っ越しても同じデジタルアドレスがつかえるとのことなのだが,1.2億人の個人と企業が複数アドレスを使いだしたらすぐに枯渇しそうだ。

他の生成AIにきくと,Geminiの説は怪しいらしいし,日本郵便自身が数百億アドレス使えるといってるらしいので,本当のところはよくわからない。まあ,不足したら後から拡張すればいいのかもしれないが。


2026年4月11日土曜日

markitdown

pdf2mdからの続き


図:マークダウンのイメージ(Geminiによる)


マイクロソフトが,いろいろなタイプのドキュメントをマークダウン化できるツール(markitdown) を出しているという。PDF,PowerPoint,Word,Excel,Images (EXIF metadata and OCR),Audio (EXIF metadata and speech transcription),HTML,Text-based formats (CSV, JSON, XML),ZIP files (iterates over contents),Youtube URLs,EPubsなどなど。いいじゃないですか。

さっそくインストールしてみた。最近のものかと思えば,2024年12月の記事があったので,前からあったのか。それでもバージョンは 0.15なので,いまひとつ進んでいないような。

% git clone https://github.com/microsoft/markitdown.git
% source myenv/bin/activate
(myenv) % pip install markitdown
(myenv) % which markitdown
/Users/koshi/myenv/bin/markitdown
(myenv) % markitdown ~/Desktop/mext.pdf -o ~/Desktop/mext.md

こんな感じで使えるには使えたのだが・・・,文部科学省のpdfファイルのせいなのか・・・
出力がまったくちゃんとしたmdファイルにはなっていないので,もとのpdfファイルの構造が見えなくなってしまっている。MacDownで確認するまでもない。

ChatGPTに相談してもあきらめ顔だった。1年前の記事だとなんとなくよさげだが,どうやらそうでもない。pdf2mdのほうがよほどましなので困ってしまう。

2026年3月31日火曜日

GLM-OCR

NDLOCR-Lite からの続き 


図:GLM-OCRのイメージ(Nano Banana 2 による)


なぜか知らないが,OCRについてのこだわりが強い。そこまで使い込むわけではないのだけれど(というか普段ほとんど使わない),イメージファイルをテキスト化することができれば,検索の俎上にのるという誘惑が大きい。

最近ネットで目にしたのが GLM-OCRである。 触れ込みはつぎのとおり
「OCRはAPIに送るもの」という発想が変わる。
・GLM-OCRは約2GB VRAMでローカル動作。
・表も数式も扱えて、Mac Studio M2 Ultraで約260 tok/s。
・ローカルモデルは驚異的なペースで改善され軽量に。
Geminiに尋ねると,ollama run glm-ocr で使えるとのこと。ollamaはインストール済みだ。
Ollama は,自分のPC上で大規模言語モデル(LLM)を動かすための軽量な実行環境だ。もう少し構造的に言うと、Ollamaは次の3つをまとめたものになる。
モデル管理:LlamaなどのLLMをダウンロード・切り替えする仕組み
推論エンジン:実際にテキスト生成を計算する部分(llama.cpp系)
APIサーバ:外部プログラムから使えるインターフェース(localhostで動く)
その後,出てくるプロンプトに対して, >>> analyze this: /Users/koshi/Desktop/qm.jpg
などとすればよい。日本語はあまりうまく認識できていなかったが,数式や表がでてくるところは,NDL-OCR より多少マシかも知れない。

2026年3月1日日曜日

NDLOCR-Lite

古典籍OCR-Liteからの続き


 図:NDLOCR-Liteの実行例の画面(蜘蛛の糸:芥川龍之介)

2月24日,国立国会図書館(NDL)からNDLOCR-Liteの公開の案内があった。
NDLOCR-Liteは、NDLOCRの軽量版を目指して開発したOCRであり、ノートパソコン等の一般的な家庭用コンピュータやOS環境で、図書や雑誌といった資料のデジタル化画像からテキストデータが作成できるOCRです。
前回の,古典籍の方はくずし字や旧字への対応を謳っていたが,今回は一般的なOCRである。前回同様,Mac版もあって,GUIアプリでもコマンドラインでも使えることが有り難い。図はApple Silicon用アプリでの実行画面である。

コマンドラインで使う方法は,NDLOCR-Liteアプリケーションのリポジトリの中にある。

source myenv/bin/activate
これでpythonの仮想環境に移動

git clone https://github.com/ndl-lab/ndlocr-lite
cd ndlocr-lite
pip install -r requirements.txt
cd src
(例1:ディレクトリからの)
python3 ocr.py --sourcedir sample-dir --output tmpdir
(例2:画像ファイルからの)
python3 ocr.py --sourceimg sample.jpg --output tmpdir

以下のような内容のテキストファイルができる。(一部抜粋引用)
或日のことでございます。お釋迦樣は極樂の蓮池のふちを、獨りでぶら〳〵
お歩きになつていらつしやいました。
池の中に咲いてゐる蓮の花は、みんな玉のやうにまつ白で、そのまん中にあ
る金色の蕋からは、何とも言へない好い匂が、絶間なくあたりへ溢れて居りま
した。

[1] ウェブアプリで使いやすくなった NDLOCR-Lite

2025年12月13日土曜日

MacのOCR(3)

MacのOCR(2)・石原純からの続き

石原純の「現代物理の基礎理論」という古いpdfファイルを見かけた。中央公論社が1943年の3月に発行した,國民學術協會編の國民學術選書の一冊である。講演録の「現代物理學の基礎理論」と書き下ろしの「自然科学の方法論について」からなる160ページ(63MB)ほどの本だ。

画像イメージのpdfなので,そのままではテキストが取り出せない。さっそく前回のショートカットによるmacOSのOCR機能を使ったコマンドに2-3ページを投入する。すぐにテキストは抽出出来たものの,解像度の悪い旧字ファイルなので,精度が悪い。

Geminiに相談したところ,
第1推奨:高性能な市販PDFソフト/OCRサービス(Adobe Acrobat Proなど)
第2推奨:Google ドライブのOCR機能(フリー)
第3推奨:macOS標準の「プレビュー」アプリ(低精度・非推奨)
とのことだった。

市販のものはコストがかかるので,GoogleドライブのOCR機能を試すことに。
(1) Googleドライブにpdfファイルをアップロード
(2) Googleドライブ中のpdfファイルを選び右クリック,Googleドキュメントを選んで開く。
(3) これでtextファイルができあがり。

・63MBの元ファイルは扱えなかったので,qpdf --split-pages=15 ishihara.pdf ishihara.pdf で分割した。20ページ分割ではエラーだったので,15ページ分割でOKとなる。
・でき上がったファイルは1文字1ページで1万ページに達したが,普通のテキストエディタにそのままコピペすれば問題なし。
・やはり旧字の誤認識が混じるがさきほどよりはましである。

肝腎の本書の内容はそこまでおもしろくはないかもしれない。


写真:石原純(理科ハウスから引用)

2025年12月12日金曜日

MacのOCR(2)

MacのOCR(1)からの続き

以前(2023年1月),MacのOCRプログラム(tesseract)を試したことなどすっかり忘れていた。全く別の方向からの話題をみかけたので,しばらく熟成させた後に試してみた。

一つは,165行のシェルスクリプト(ocr.sh)である。
「純bash → 一時的にAppleScriptAppleScriptObjC)を起動 → macOSのVision/QuartzフレームワークでOCR」という三層構成。入出力は「画像(jpg/png)またはPDF → 標準出力に認識テキスト。引数で言語(ja/en)とPDFをラスタライズするDPIを切り替え。制御のキモは、PDFはページごとに指定DPIで画像化→白背景で正規化→VisionでOCR、画像も同様に白背景で正規化してからOCR、という“前処理の徹底”と、“Visionへの最小限・最適な設定”にある。
しかしこれでは縦書き日本語がうまくいかないことがあるらしい。そこで示されたのが,macOSのビルトインOCR機能をmacOSの「ショートカット」アプリで呼び出すというものだ。ショートカットは,他のジョブでもこれまで何度もトライしてきたのだが,すべて途中で挫折してしまった。ちゃんと勉強せずに行き当たりばったりでやるとそうなる。

今度もだめかなと半分あきらめつつ,ChatGPTにやり方を繰り返し教えてもらうことで,なんとかうまくいった。Scratchみたいなビジュアルプログラミング言語はどうも苦手だ。年寄りにはよけい難しく感じる。普通のエディタでテキスト入力したいよ。こうしてつくったスクリプトが,Extract_text_from_files(下図参照)だ。

これをコマンドラインから次のように起動する。

shortcuts run "Extract_text_from_files" -i ~/sample.pdf -o ~/sample.txt  


入力ファイルは,pdf,jpg,png である。出力ファイルを省略すると標準出力に流れる。実際に試したところ,縦書きのpdfファイルもjpgファイルもpngファイルもうまくいっている。認識精度はtesseractよりもずっとよかった。





図:はじめてのショートカット


2025年11月18日火曜日

こっき(3)

こっき(2)からの続き

Q(koshix):
(旧ファイル kokki.html を添付)
外部サイト("https://restcountries.com/v3.1/all")の国旗データにアクセスできなくなりました。そこで,このサイトはつかわないことにします。flagpedia.netから国連加盟国の国旗のsvgデータを持ってきました。 250カ国ほどの国旗データはjp.svgのように,二文字の国旗コード名のsvgファイルとして flagsディレクトリ以下に格納されています。 このローカルデータを用いてもとのkokki.htmlと同等の機能を実現するhtmlファイルを作成してください

A(ChatGPT-5):
もとの kokki.html は restcountries.com に依存して国名や地域情報を取得していましたが、今回は 外部APIを使わず、flags/xx.svg(ISO α2コード)だけで動く版に作り替えます。(以下回答略)

Q(koshix):
表示部で国記号(国記号)となっているのを,国記号(日本語の国名)になるようにしてください。

A(ChatGPT-5):
了解しました。いまのHTMLでは表示部分を「JP(日本)」のように 国記号(日本語の国名) に変更したい、ということですね。(以下回答略)

Q(koshix):
改善されていませんが。

A(ChatGPT-5):
ごめんなさい。原因は「日本語名の辞書が無いと、itNameJa() が国コードをそのまま返す」仕様のままだったことです。(以下回答略)

Q(koshix):
修正した全コードを下さい。
A(ChatGPT-5):
了解です。ご指定の「国記号(日本語の国名)」表示に修正済みの全体コードをお渡しします。外部API不要・flags/xx.svgのみで動作し、日本語名は Intl.DisplayNames で自動生成(辞書があれば優先)します。(以下回答略)

Q(koshix):
表示領域が全世界だけイキの状態です。現行の5つの地域ごとに選択することはできないのですか?
A(ChatGPT-5):
ありがとうございます。原因は、地域フィルタが「flags/regions.json が無いと無効化」される設計のままだったことです。(以下回答略=ほぼ希望どおりのものに)



図:kokki.htmlの例


P. S. なお,その後かざはチャンは国旗への関心を失ってしまい,どの国旗ももう憶えていないらしい。チーン。

2025年9月19日金曜日

Welcome to BUNRAKU!

国立文楽劇場の爽秋文楽特別公演は,9月6日から10月14日までと,例年(去年は11月2日〜24日)より早期に始まり長期間にわたって開催される。これは10月13日まで開催される2025大阪・関西万博対応の特別仕立てである。

プログラムは次のようになっている。
Aプロ
・Welcome to BUNRAKU!
・恋女房染分手綱(道中双六の段,重の井子別れの段)
・日高川入相花王(渡し場の段)
Bプロ
・心中天網島(北新地河庄の段,天満紙屋内の段,大和屋の段,道行名残の橋づくし)
Cプロ
・Welcome to BUNRAKU!
・曾根崎心中(生玉社前の段,天満屋の段,天神森の段)
前半の9月25日までが,A-B-C,後半の9月26日からが,C-B-A という順に上演される。

今回は,外国人向けの英語での文楽の概要説明(約10分)Welcom to BUNRAKU! が含まれるAプロを観賞した。恋女房染分手綱も日高川入相花王もこれまで何度か見ている演目だ。

いつもより上演期間が倍近くに延びているためか,731席の国立文楽劇場は3-4割の入りだった。外国人は10人程度なので,3-4%というところか。万博の外国人観光客をターゲットとしているため,新たな試みとして従来の日本語字幕投影のかわりに,スマホアプリによる日本語・英語字幕表示システムが取り入れられた。

EG-Gというアプリで,手元に字幕が表示される。ところが,これはネットワークを使わないので,端末は機内モードにしておく。アプリで端末のマイク利用をONにしておくと,劇場内に流れる非可聴音で信号を流し,これを聞き取って端末に字幕を表示するというものらしい。

問題は,舞台を見るときは眼鏡をかけているので,手元だと眼鏡を外さないといけないということ。やはり視線移動が多くなるとちょっとしんどい。これが耳からの情報ならばOKなのだけれど。端末側でイアホンを利用しているかどうかが判別できて,なおかつスピーカーから音が出ないという設定ができればいいけど。AirPods とか指定すればできそうではあるが。

肝腎の文楽の中身だけれど,日高川を泳ぐ清姫のウロコ模様の帯着物がいまいちきれいに伸びてはいなかったのが残念。



図:EG-Gの画面(2025.9.17 撮影)


2025年7月18日金曜日

Japan DashBoard

7月10日,内閣府とデジタル庁が「Japan Dashboard(経済・財政・人口と暮らしに関するダッシュボード)とデータカタログ」を公開した。
普通だと,ダッシュボードのトップページへのリンクがあって,そこにアクセスして話が進んでいくようなものだけれど,デジタル庁の該当ページは何だか面倒なことになっていた。
1.指標の分類
2.Japan Dashboard
 ・指標のデータをみる
 ・1つの指標を都道府県ごとにみる
 ・2つの指標の関係性をみる
 ・4つの指標の推移を並べてみる
3.データカタログ
 (1) 1つの指標のデータをコピーして利用する
 (2) 複数の指標を一括ダウンロードする
4.関連資料
 (1) Japan Dashboardの見方と操作方法
 (2)「見える化」ポータルサイトのリニューアル方針
5.留意事項
この目次がいきなり登場するということは,ここがダッシュボードなのか?ここは単なるお知らせのページではなかったのか?わからない。あわててリンク先の内閣府のページに行くと内閣府側のまったく同じものに誘導された。わかりにくすぎる。とにかく,
691の指標を7つの大分類と62の中分類に分けて整理しています。
人口:人口、婚姻・出生、高齢者割合等
経済:県内総生産、就業・労働、所得・課税等
教育:学校数・教員数、学校のICT環境等
社会保障:医療体制、医療費、検診受診率等
暮らし:安全、居住等
社会基盤:社会基盤
地方財政:基金、歳出・歳入等
について,都道府県別のデータ,2つの指標の相関と年次推移,4つの指標の比較などが上記の事例から選んで試せることだけがわかった。遊んでいるうちに思わぬ発見をするかもしれない。それにしても面倒だ。AI チャットボットに対話的に依頼するシステムにしてほしい。



図:Japan Dashboard で扱われるデータ項目一覧

2025年7月14日月曜日

jReadability

量子コンピュータからの続き

放送大学の数理・データサイエンス・AI講座をみていたら,自然言語処理の話の中で,jReadability というウェブアプリが紹介されていた。ICT・AI・言語教育の科研グループが開発しているもののようだ。

日本語学習者向けのもので,日本語文章難易度判定システム(jReadability,難易度6段階判定),日本語学習者作文評価システム(jWriter,到達レベル5段階判定),日本語教育語彙集(JEV,18000語),機能後用例文データベース(はごろも)の4つのシステムから成り立っていて自由に使える。

早速,自分のブログテキストを日本語文章難易度判定システムに入れてみた。400字から1000字のテキストを受け付けるようになっている。「可視化機能を使用する」にチェックをいれると,ワードクラウド,語彙ネットワーク,意味階層図を出力してくれる。標準だと,テキスト情報,テキスト詳細,語彙リストが出てくる。

さて,「量子コンピュータ(13文,962字,229異形態素)」のリーダビリティは2.75であり,中級後半(ややむずかしい)となった。いいのか悪いのか。ひらがなが半分,和語が2/3で漢語が1/3,普通名詞が1/3で助詞助動詞が1/3。



図:ワードクラウドの結果

2025年6月12日木曜日

HyperCard

アップルと私からの続き

6月5日,HyperCard(1987-1998)を産みだしたビル・アトキンソン(1951-2025)が亡くなった。ビル・アトキンソンは,先日テレビでみた映画スティーブ・ジョブス(2013)にも本人とよく似た役者さんが登場していた。

1988年に大阪教育大学にMacintosh IIを40台導入して使い始めようとしていたとき,HyperCardがインストール済みかどうかは我々には大きな問題だった。というのも,そのハイパーテキストスタックの例をみて,これは教育に使えると直感したからだ。HyperCardは1987年に発表されたばかりだったが,無事にインストールされていた。

その後,自分の研究室に入った代々のMacintoshにもしばらくHyperCardがのっていた。やったー。しかし,残念ながらそれだけで満足してしまい自分でHyperCardスタックを開発することは全くなかった。ハイパーテキストを実際に自分で操って教育用コンテンツを作るようになるには,WorldWideWebの登場によるHTMLファイルの作成まで待たなければならなかった。


京大の情報科学演習の非常勤を担当していたころ,WWWブラウザ普及の嚆矢となるNSCAMosaicが登場した。筒井多圭志さんに,ハイパーテキストの重要性を初めて認識したのはHyperCardを見たからだというと,ハイパーテキストはTexinfoで実装されているよと教えてもらった。

なお,ビル・アトキンソンは,MacPaintでも知られるQuickDraw を開発し,MacintoshのGUIを成功に導いた人だ。以下,小龍茶館から引用。
1987年8月11日から1992年まで、Appleは販売した全てのMac(Macintosh)にHyperCardをプレインストールしていました。またそれ以外の時期に発売されたMacにも、49ドルという価格でHyperCardを購入できてインストールすることが可能でした。そして2004年3月、HyperCardは正式にAppleのプラットフォームから”引退”し、Appleとコンピュータの歴史にその名が刻まれることになります。


図:HyperCardのホーム画面(ITmediaから引用)

[1]HyperCard on the Archive(Internet Archive)
[2]HyperCard Stacks(Internet Archive)
[5]HyperCard AI(平野友康)
[6]青空のリスタート(富田倫生)

2025年2月21日金曜日

こっき(2)

こっき(1)からの続き

国旗アプリを改良しようと考えた。1ステップ前の国旗に戻れるようにするものだ。最初は,左下の1/4×1/4領域に,前回表示した国旗の小さなイメージを表示させてそこをクリックすると前の表示に戻るようにするものだ。国名は通し番号をつけて右下に移動した。

ChatGPT o3-mini-highにお願いしたところ,何度かのやりとりの後に目的のものはできたにはできたが,国旗が2つも表示されているのは子どもにはわかりにくそうだ。やり直し。

Q(koshix):
国旗表示アプリ
以下のウェブアプリに修正を加えてください。
(1) 各国旗には次の3つの番号を持ちます。(a) アルファベット順の通し番号,(b) アイウエオ順の通し番号,(c) アプリ起動後にその国旗が最初に表示されたときの通し番号
(2) カタカナの国名表示部分を,通し番号:カタカナ国名 の形に修正してください。このときの通し番号は,表示モードに対応したものとします。
(3) 右下に半透明グレーのボタン領域を設定してください。その機能は後で説明します。まずは,(1) (2) を実装した全体コードをお願いします。
なお,修正前のコードは以下のとおりです。

Q(koshix):
ボタン領域を「もどる」というなまえにして,ここをクリックすると選択された領域で表示されている国旗より通し番号がワンステップ小さいものに戻って表示するようにしてください。

これで目的のものはできた。361行のウェブアプリである。やはりどういうロジックにするかを想定しながらプロンプトを考えるのが重要だ。前回は単なる仕様だけで依頼したので,うまく機能しなかったので結構モチャついた371行



図:kokki.htmlのiPhoneでの実行画面

以下が,修正版のkokki.htmlのソースコードだ。108行目あたりのkazaha.jpgを自分のイメージファイルに変えて,kokki.htmlと同じフォルダに設置して,ブラウザで閲覧すればOKだ。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>かざは の こっき</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      background-color: #f0f0f0;
      height: 100%;
      font-family: sans-serif;
    }
    /* トップページ(スタート前) */
    #top-page {
      text-align: center;
      padding: 20px;
    }
    #top-page h1 {
      font-size: 2em;
      margin-bottom: 20px;
    }
    #top-page img {
      width: 437px;
      height: 377px;
      margin-bottom: 20px;
    }
    /* スタートボタン */
    #start-button {
      padding: 12px 24px;
      font-size: 1.5em;
      border: none;
      border-radius: 8px;
      background-color: #007aff;
      color: #fff;
      cursor: pointer;
    }
    /* 国旗表示ボックス */
    #flag-container {
      width: 90vw;
      height: 70vh;
      margin: 5vh auto;
      position: relative;
      background-color: #000;
      border: 5px solid #fff;
      box-shadow: 0 4px 8px rgba(0,0,0,0.5);
      cursor: pointer;
      display: none; /* スタート前は非表示 */
      touch-action: manipulation;
    }
    #flag-container img {
      width: 100%;
      height: 100%;
      object-fit: contain;
      opacity: 0;
      transition: opacity 0.8s ease-in-out;
      position: absolute;
      top: 0;
      left: 0;
    }
    #country-name {
      position: absolute;
      bottom: 10px;
      left: 10px;
      background: rgba(255, 255, 255, 0.7);
      padding: 4px 8px;
      border-radius: 8px;
      font-size: 1.2em;
      z-index: 10;
    }
    /* 設定パネル */
    #control-panel {
      position: absolute;
      top: 10px;
      left: 50%;
      transform: translateX(-50%);
      background: rgba(255,255,255,0.9);
      padding: 8px;
      border-radius: 8px;
      z-index: 10;
      display: flex;
      gap: 10px;
      align-items: center;
    }
    #control-panel select {
      font-size: 1em;
      padding: 4px;
    }
    /* 右下の半透明グレーのボタン領域(もどるボタン) */
    #button-area {
      position: absolute;
      bottom: 10px;
      right: 10px;
      background: rgba(128, 128, 128, 0.5);
      padding: 10px;
      border-radius: 8px;
      z-index: 10;
      cursor: pointer;
      user-select: none;
    }
  </style>
</head>
<body>
  <!-- トップページ(初回表示) -->
  <div id="top-page">
    <h1>かざは の こっき</h1>
    <img src="kazaha.jpg" alt="かざはの顔">
    <br>
    <button id="start-button">スタート</button>
  </div>
  
  <!-- 国旗表示エリア -->
  <div id="flag-container">
    <img id="flag-image" src="" alt="国旗">
    <div id="country-name"></div>
    <div id="control-panel">
      <div>
        <label for="order-select">表示順序:</label>
        <select id="order-select">
          <option value="alphabetical">アルファベット順</option>
          <option value="japanese">アイウエオ順</option>
          <option value="random">ランダム</option>
        </select>
      </div>
      <div>
        <label for="region-select">表示領域:</label>
        <select id="region-select">
          <option value="all">全世界</option>
          <option value="eastAsiaOceania">東アジア〜オセアニア</option>
          <option value="southWestAsia">南〜西アジア</option>
          <option value="europe">ヨーロッパ</option>
          <option value="africa">アフリカ大陸</option>
          <option value="americas">アメリカ大陸</option>
        </select>
      </div>
    </div>
    <!-- 右下の「もどる」ボタン領域 -->
    <div id="button-area">もどる</div>
  </div>

  <!-- Kuroshiro と Kuromoji の読み込み -->
  <script src="https://unpkg.com/kuroshiro@1.1.3/dist/kuroshiro.min.js"></script>
  <script src="https://unpkg.com/kuroshiro-analyzer-kuromoji@1.1.0/dist/kuroshiro-analyzer-kuromoji.min.js"></script>
  
  <script>
    // グローバル変数
    let allCountries = [];
    let countries = [];
    let currentIndex = 0;
    let kuroshiro;
    let randomDisplayCounter = 1; // ランダムモードで初回表示されたときの番号用
    
    // 初期化処理全体をまとめる
    async function initializeApp() {
      // トップページを非表示、国旗エリアを表示
      document.getElementById("top-page").style.display = "none";
      document.getElementById("flag-container").style.display = "block";
      
      // Kuroshiro の初期化
      try {
        kuroshiro = new Kuroshiro();
        await kuroshiro.init(new KuroshiroAnalyzerKuromoji({
          dictPath: 'https://unpkg.com/kuromoji@0.1.2/dict/'
        }));
        console.log("Kuroshiro initialized");
      } catch (error) {
        console.error("Kuroshiro initialization failed:", error);
      }
      
      // 国データの取得
      await fetchCountries();
      // イベントリスナーの設定
      setupEventListeners();
    }
    
    // 国データ取得
    async function fetchCountries() {
      try {
        const response = await fetch("https://restcountries.com/v3.1/all");
        const data = await response.json();
        allCountries = await Promise.all(data.map(async country => {
          const flagUrl = country.flags && country.flags.png ? country.flags.png : "";
          const nameEn = country.name && country.name.common ? country.name.common : "";
          const jpName = (country.translations &&
                          country.translations.jpn &&
                          country.translations.jpn.common) ? country.translations.jpn.common : nameEn;
          let nameKatakana = "";
          try {
            nameKatakana = await kuroshiro.convert(jpName, { to: "katakana", mode: "normal" });
          } catch (err) {
            console.error("Conversion error:", err);
            nameKatakana = jpName;
          }
          return {
            flag: flagUrl,
            name_en: nameEn,
            name_katakana: nameKatakana,
            region: country.region || "",
            subregion: country.subregion || ""
          };
        }));
        // 不要なデータの除外
        allCountries = allCountries.filter(c => c.flag && c.name_en && c.name_katakana);
        
        // 各国旗に対してグローバルな番号を付与
        // (a) アルファベット順の通し番号
        let sortedAlpha = [...allCountries].sort((a, b) => a.name_en.localeCompare(b.name_en));
        sortedAlpha.forEach((country, index) => {
          country.numAlpha = index + 1;
        });
        // (b) アイウエオ順(カタカナ順)の通し番号
        let sortedKatakana = [...allCountries].sort((a, b) => a.name_katakana.localeCompare(b.name_katakana, "ja"));
        sortedKatakana.forEach((country, index) => {
          country.numKatakana = index + 1;
        });
        // (c) ランダムモード用(初回表示時に設定)の番号は未設定状態に
        allCountries.forEach(country => {
          country.numDisplay = null;
        });
        
        // 初期のフィルタ・ソート処理
        filterCountries();
        sortCountries();
        displayCountry();
      } catch (error) {
        console.error("Error fetching countries:", error);
      }
    }
    
    // 表示領域でフィルタ
    function filterCountries() {
      const regionValue = document.getElementById("region-select").value;
      if (regionValue === "all") {
        countries = allCountries.slice();
      } else if (regionValue === "eastAsiaOceania") {
        countries = allCountries.filter(c => 
          (c.region === "Oceania") ||
          (c.region === "Asia" && (c.subregion === "Eastern Asia" || c.subregion === "South-Eastern Asia"))
        );
      } else if (regionValue === "southWestAsia") {
        countries = allCountries.filter(c => 
          c.region === "Asia" && !(c.subregion === "Eastern Asia" || c.subregion === "South-Eastern Asia")
        );
      } else if (regionValue === "europe") {
        countries = allCountries.filter(c => c.region === "Europe");
      } else if (regionValue === "africa") {
        countries = allCountries.filter(c => c.region === "Africa");
      } else if (regionValue === "americas") {
        countries = allCountries.filter(c => c.region === "Americas");
      }
      currentIndex = 0;
    }
    
    // 表示順序でソート
    function sortCountries() {
      const order = document.getElementById("order-select").value;
      if (order === "alphabetical") {
        countries.sort((a, b) => a.name_en.localeCompare(b.name_en));
      } else if (order === "japanese") {
        countries.sort((a, b) => a.name_katakana.localeCompare(b.name_katakana, "ja"));
      } else if (order === "random") {
        // ランダムモードでは Fisher-Yates シャッフルを実施
        for (let i = countries.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [countries[i], countries[j]] = [countries[j], countries[i]];
        }
      }
      currentIndex = 0;
    }
    
    // 現在の国を表示
    function displayCountry() {
      if (countries.length === 0) {
        console.error("No countries available for the selected region.");
        document.getElementById("country-name").textContent = "データなし";
        document.getElementById("flag-image").src = "";
        return;
      }
      const currentCountry = countries[currentIndex];
      
      // 表示モードに応じた番号を取得
      const orderMode = document.getElementById("order-select").value;
      let displayNumber;
      if (orderMode === "alphabetical") {
        displayNumber = currentCountry.numAlpha;
      } else if (orderMode === "japanese") {
        displayNumber = currentCountry.numKatakana;
      } else if (orderMode === "random") {
        if (!currentCountry.numDisplay) {  // 初回表示時のみ番号を付与
          currentCountry.numDisplay = randomDisplayCounter++;
        }
        displayNumber = currentCountry.numDisplay;
      }
      
      // 国旗画像の切替演出
      const flagImage = document.getElementById("flag-image");
      flagImage.style.opacity = 0;
      setTimeout(() => {
        flagImage.src = currentCountry.flag;
        // 「通し番号:カタカナ国名」の形式で表示
        document.getElementById("country-name").textContent = displayNumber + ":" + currentCountry.name_katakana;
        flagImage.onload = () => {
          flagImage.style.opacity = 1;
        };
      }, 800);
    }
    
    // イベントリスナーの設定(タッチ対応の場合は touchend を優先)
    function setupEventListeners() {
      const flagContainer = document.getElementById("flag-container");
      
      function nextCountry() {
        currentIndex = (currentIndex + 1) % countries.length;
        displayCountry();
      }
      
      // タッチまたはクリックで次の国を表示
      if ('ontouchstart' in window || navigator.maxTouchPoints) {
        flagContainer.addEventListener("touchend", function(e) {
          nextCountry();
        }, false);
      } else {
        flagContainer.addEventListener("click", function(e) {
          nextCountry();
        }, false);
      }
      
      // 表示順序・表示領域の変更時の再ソート/再表示
      document.getElementById("order-select").addEventListener("change", () => {
        sortCountries();
        displayCountry();
      });
      document.getElementById("region-select").addEventListener("change", () => {
        filterCountries();
        sortCountries();
        displayCountry();
      });
      
      // 「もどる」ボタンのイベント設定
      const buttonArea = document.getElementById("button-area");
      
      // タッチイベントに対応
      buttonArea.addEventListener("touchend", function(e) {
        e.stopPropagation();
        e.preventDefault();  // タッチ操作時のデフォルト動作を防止
        if (countries.length > 0) {
          currentIndex = (currentIndex - 1 + countries.length) % countries.length;
          displayCountry();
        }
      }, false);
      
      // PCなど、タッチ以外のデバイス用のクリックイベントも残す
      buttonArea.addEventListener("click", function(e) {
        e.stopPropagation();
        if (countries.length > 0) {
          currentIndex = (currentIndex - 1 + countries.length) % countries.length;
          displayCountry();
        }
      }, false);
    }
    
    // スタートボタンのイベント設定(pointerup イベントを使用)
    document.getElementById("start-button").addEventListener("pointerup", () => {
      initializeApp();
    });
  </script>
</body>
</html>


2025年2月20日木曜日

こっき(1)

まだ1歳10ヶ月の風葉ちゃんは国旗を覚えるのが得意だ。GGが知らない国の国旗を沢山知っている。ママからのリクエストで国旗アプリを考えることになった。市販のスマホアプリは1-2歳向けではないのだ。要求仕様は次のようなものになる。

(1) 世界の国旗が地域別(または全世界)に表示される。
(2) その下にはカタカナの国名が表示されている。ママだけが読める。 
(3) タップすると順に次の国旗が表示される。国名がわからなければママが解説する。
(4) 表示は,アルファベット順,アイウエオ順,ランダムとする。
(5) 地域は,東アジア・オセアニア,西・南アジア,ヨーロッパ,アフリカ大陸,アメリカ大陸とする。

本物のiPhoneアプリはハードルが高すぎるので,とりあえずWebアプリにしよう。もちろん,高齢者の脳力に頼っていては死ぬまでにできあがらないので,ChatGPT o3-mini-high にお願いするわけだ。自分が入れた一連のプロンプトは以下のとおりである。

Q(koshix):
幼児向けの国旗のウェブアプリを作ってください。
お母さんと子どもが一緒に遊べるものです。
・国旗の画面が大写しになります。
・その画面に国名が小さく表示されます。
・スライドするとつぎの国旗にうつります。
・表示順序をアルファベット順,五十音順,ランダムに設定変更できます。
国連に加盟しているすべての国や地域のフリーのイメージデータに
アクセスして表示できるようにします。

Q(koshix):
国名はカタカナにしてください。
クリックしたら次の国旗に進むようにしてください。それまでは静止です。

Q(koshix):
画面が真っ暗で表示されず,クリックしても進まないのですが。

Q(koshix):
(1) 国旗の表示が画面いっぱいになっているので,もう少し小さめにして余白領域を作ってください。
(2) 表示範囲を,東アジア〜オセアニア・南〜西アジア・ヨーロッパ・アフリカ大陸・アメリカ大陸の5領域および全世界の6つから選択できるようにしてください。
(3) iPhoneにこのhtmlファイルを転送して実行しようとすると,スタート時点でつまづいて進みません。iPhoneでも使えるように対処可能でしょうか。

Q(koshix):
ありがとうございます。機能はほぼ希望通りになりました。しかし,iPhoneでは画面が真っ暗のままで進まずに停まっています。どこかへのアクセスが拒否されているような感じです。どうすればよいでしょうか。

Q(koshix):
iPhoneだけでなんとかしたいので,外部にhttps対応サーバを準備することができないのですが。マウスクリック操作の機能部分ははタッチ操作に対応するようになっていますかね。

Q(koshix):
1.ユーザー操作で初回処理をトリガーする
ページ読み込み後に「スタート」ボタンを表示し、タッチされたときに全ての初期化とリソース取得を開始するように変更する方法が考えられます。これなら、iOS側での自動起動制限を回避できる場合があります。
2.ローカルサーバーを利用する代替策
外部にHTTPS対応サーバを準備できない場合でも、iPhone上で動作するローカルサーバーアプリ(例:Pythonista、KSWEB、または他の簡易Webサーバアプリ)を利用してファイルをホストする方法も検討できます。

これらの場合の具体的な手順を詳細に説明してください。

Q(koshix):
localでウェブサーバを立ち上げ,iphoneでアクセスすることに成功しました。

Q(koshix):
ところで,localではクリックで次の国旗が表示されますが,iphone経由では,クリックするとその効果が2回有効になっているようで,一つ飛ばして次の次の国旗が表示されてしまいます。どうすればいいでしょうか。

Q(koshix):
1の方法をとりたいのですが,元のコードで言うとどの部分の修正になりますか。修正後の全コードを教えてもらったほうが助かります。

Q(koshix):
最初のスタートで次に進むことができなくなりました。

Q(koshix):
ありがとうございます,うまくいきました。
トップ頁に「かざは の こっき」というタイトルをいれて,かざはの顔写真 kazaha.jpg  437x377 ピクセルを表示するように修正できますか。 kazaha.jpg はkokki.html と同じフォルダにあります。


図:世界の国旗(外務省から編集して引用)

pythonでローカルのウェブサーバを立ち上げ,ngrokでトンネルを設定すると,外部からローカルウェブサーバのコンテンツにアクセスすることができる。そこで,kokki.html(296行)とkazaha.jpgを置いたディレクトリでローカルウェブサーバを立ち上げておけば,ngrokが指定するURLでiPhoneからこの国旗Webアプリが使えるようになった。
python3 -m http.server 8000
ngrok http 8000
https://zzzzzzzzzz.ngrok.io/kokki.html 
問題は,ngrokを無料で使っている限りこのURLが永続的ではないことだ。sakuraインターネットに眠らせてあるWebサイトを起すべきだろうか。ChatGPTを使えば一日一ウェブアプリを公開することができる。

(付)http.server ファイルの中身
import http.server
import socketserver
PORT = 8000
class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
    def end_headers(self):
        # iOS Safari のキャッシュ対策のため
        self.send_header("Cache-Control", "no-store, no-cache, must-revalidate")        http.server.SimpleHTTPRequestHandler.end_headers(self)
Handler = MyHttpRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("Serving at port", PORT)
    httpd.serve_forever()

2025年2月9日日曜日

立ちタイム

家人から「高齢者が1日20分程度立つ時間や機会を作ることは,立つ能力を維持し寝たきりになることを防ぐのに役立つ」と聞いた。調べてみるとGoogleもそう言っている。

老人が立っている時間を計測するアプリを作ると儲かるのではないかと考えた。考えるだけはタダなので。こんな場合,推論モデルの生成AI(DeepSeek R1とChatGPT o1)に聞いてみるといいかもしれない。なお「立ちタイム」というアプリ名はDeepSeekの提案だ。

Q(koshix):
老人の健康を維持するためには1日に20分以上立っていることが必要だということを聞きました。そこで,(1) スマートフォンだけ,あるいは,(2) スマートフォンと他のウェアラブルデバイスとの組み合わせ,によって,人が立っている時間を記録するアプリを作りたいと考えました。どのような原理とセンサーを用いれば,人間が立っている時間を測定することができるか,そのアイディアと具体的な実現方法を考えてみてください。

A(DeepSeek R1):
人間が立っている時間を測定するためのアプリ開発には、以下のような原理とセンサーの組み合わせが考えられます。スマートフォン単体と複数デバイス併用の両ケースについて具体的に説明します。

【基本原理】
立位状態の判定には「姿勢」「動き」「重力方向」の3要素を組み合わせます。特に重要なのは:
(1) 重力ベクトルの方向(スマホの傾き)
(2) 身体の垂直軸方向の加速度
(3) 高さ変化の検出(オプション)

【ケース1:スマートフォン単体での実現方法】
使用センサー
(1) 加速度センサー
・重力方向の検出:Z軸方向の重力値がほぼ1G(9.8m/s²)かつ安定している場合、直立状態と推定。
・動きの検出:3軸加速度の変動が少ないとき「静止立位」、周期的な変動があれば「歩行中」と区別。
(2) ジャイロセンサー
・姿勢の持続時間:デバイスの傾き角度が一定範囲(±15度以内)を維持した時間を計測。
 例:スマホがポケット内で縦方向に安定 → 立位と判断。
(3) 気圧センサー(搭載機種限定)
・相対高度変化:座る/立つの0.5m程度の高さ差を検出(例:±5hPaの変化をトリガーに)。

【アルゴリズム例】 python # 疑似コード (略)

【課題と対策】
・誤検知対策:椅子に座ったままスマホを机に置くケース → 照度センサーで「ポケット内/手持ち」を判別。
・省電力化:サンプリング間隔を調整(例:静止時は1Hz、動き検出時は10Hz)。

【ケース2:スマートフォン+ウェアラブルデバイスの組み合わせ】
追加センサー
(1) スマートウォッチの心拍数センサー
・静脈パターン変化:手首が心臓より下(垂れ下がった状態)で静脈圧が上昇 → 立位の補助指標。
(2) 骨伝導センサー(イヤホン)
・関節音の検出:膝の伸展時の「ポキッ」という微小な音を検出(実験段階の技術)。
(3) 足首バンドの圧力センサー
・足底荷重検出:直立時に均等な圧力分布が持続する特性を利用。

データ融合の例
複数デバイスのデータを組み合わせて信頼性向上:

【ユーザビリティ向上策】
(1) キャリブレーション機能
・初回設定時に「立つ」「座る」を指示し、個人のデバイス保持癖を学習。
(2) 誤検知フィードバック
・ユーザーが手動で誤りを修正すると、AIモデルが継続学習(Active Learning)。
(3) 省電力設計
・エッジAIで処理(クラウド依存せず)、TensorFlow Liteモデルを使用。

【検証方法】
(1) ベンチマークテスト
・カメラ映像とセンサーデータを同期記録し、教師データとして使用。
(2) シニア向け調整
・ゆっくりした動作に対応するため、状態遷移の判定閾値を緩和(例:立ち上がりに5秒以上かかるケース)。

【発展的な応用】
転倒予防:ふらつき検出(加速度の急激な揺れ)と連動。
血圧管理:立位時間と健康データ(Apple Health/Google Fit連携)を相関分析。

このように、スマートフォンの基本センサーを活用しつつ、ウェアラブルデバイスを組み合わせることで、より正確な立位時間の測定が可能になります。特に高齢者向けには「誤検知の少なさ」と「操作の簡便さ」のバランスが重要です。


A(ChatGPT o1):
以下では、まず「人が立っている状態をどのような原理で判定できるか」について、考え方をステップバイステップで整理し、そのうえで(1)スマートフォンのみを用いるケースと(2)スマートフォン+ウェアラブルデバイスを用いるケースの具体例を示します。

1.コンテキストと前提条件
「人が立っている状態の検知」は、腰や胸の位置にあるデバイスがどのような姿勢にあるか、あるいは体重のかかり方・重心の変化などをベースに判断できます。
スマートフォンだけで測定する方法と、ウェアラブルデバイスを追加で使う方法では、利用可能なセンサーや精度、実装の容易さが異なります。
特に高齢者が使う場合、「装着位置をどれだけ徹底できるか」「デバイスの充電や操作が煩雑にならないか」など、実際の利用シーンを考慮する必要があります。

2.人が立っている状態を推定するための主な原理
(1) 加速度計(加速度センサー)
・本体が垂直方向にどの程度加速度を受けているか、また姿勢がどう変化しているかを推定する。
・スマートフォンや多くのウェアラブルに標準搭載されているセンサー。
(2) ジャイロセンサー(角速度センサー)
・デバイスの回転や傾きの変化を検知する。
・姿勢の変化(座っている・立ち上がる・歩いている)などを判定するときに有用。
(3) 気圧センサー(バロメーター)
・スマートフォンやスマートウォッチに搭載されている場合、上下方向の移動(高さの変化)を推定できる。
・立ち上がった・しゃがんだなど、高さの小さな変化を捉えられる可能性がある(ただし微妙な変化をしっかり捉えられるほど精度が高いかは機種依存)。
(4) 近接センサー / 人感センサー / カメラ
・外部環境との距離や動きを把握して、立っている状態を推測する方法もあるが、スマホの近接センサーだけでは精度が不十分なことが多い。
・カメラを使う場合、人の姿勢推定アルゴリズム(Pose Estimation)などを適用する方法はあるが、バッテリー消費やプライバシー面で課題がある。
(5) 歩数センサー(ペドメーターAPI) と静止判定
・スマートフォンやスマートウォッチは、OS側で歩行や静止をある程度分類してくれるAPIがある(例:iOSのCore Motion、AndroidのActivity Recognition API など)。
・立って「静止」している場合と「座っている」場合を区別できるかは精度やアルゴリズム次第。ただしモーションAPIで「Standing」を直接判定できるとは限らないため、追加ロジックが必要。

3.スマートフォンのみを用いる場合のアイディアと実装方法
3-1. 装着場所の想定
・スマートフォンを腰の位置(ベルトクリップやポケット)に入れておく。
・「なるべく毎日同じ場所に装着する」ことを利用者に徹底してもらう。
3-2. センサー活用の流れ
(1) 加速度センサーによる傾き・姿勢検知
・加速度センサーの値から、スマホがほぼ垂直にあるか(重力方向と端末の姿勢方向が一致しているか)を確認する。
・人間が立っているときは、腰ベルト付近でスマホが縦方向に近い姿勢になりやすい。一方で、座るときはスマホの角度が変わる(背もたれとの関係や腿との角度など)。
(2) ジャイロセンサーによる動きの検知
・立ち上がる、座るといった動作時の角速度変化を検知し、姿勢遷移を検出する。
(3) Activity Recognition APIの利用(Android/iOS)
・端末のモーション処理APIを用いて、「歩行中」「静止中」などのステータスを取得。
・「静止中」かつ「端末が垂直に近い姿勢」という条件を満たす場合を「立っている」とみなすなどのロジックを組む。
3-3. 実装の例
(1) 単純ルールベース
・一定時間ごと(1秒単位など)に加速度ベクトル(x, y, z)を取得して、そのベクトルが重力方向(9.8m/s^2)とどの程度ズレているかを計算する。
・そのズレが小さい(つまり端末が垂直に近い)&歩数変化がない(=歩いていない)状態が連続した場合を「立位状態」とカウントする。
(2) API活用 + フィルタリング
・OS標準のActivity Recognition(例: Androidなら「STILL」「WALKING」「ON_FOOT」等)を取得。
・STILLの状態が一定秒数続き、スマホの傾きが一定範囲内なら「立位」とカウント。傾きが大きければ「座位」と推定。
・データを5秒ごとにログ化し、合計時間を算出。
3-4. 課題と工夫
・スマートフォンをテーブルやカバンの中に置きっぱなしにすると、加速度が検知されず誤検出が増える。
・スマートフォンの装着位置に依存するため、利用者の協力が必要になる。
・デバイスが古い場合はセンサー精度が低いことがある。

4.スマートフォン+ウェアラブルデバイスを用いる場合のアイディアと実装方法
4-1. 使えるウェアラブルの例
(1) スマートウォッチ
・加速度・ジャイロ・気圧センサーが入っていることが多い。
・歩数計測、立ち上がり、座っている時間のログ機能などが標準アプリに付いていることもある。
(2) スマートシューズ
・足裏の圧力センサーで、足に体重がかかっているかを検知できる。
・立っている・座っているの判定精度が比較的高い。
(3) 腰ベルト型の専用装置
・リハビリや介護分野で市販されている、姿勢判定に特化したデバイスも存在する。
4-2. スマートフォンとの連携によるメリット
(1) 装着の自由度
・スマートフォンはポケットなどに入れたままでも、ウェアラブル側のセンサーから姿勢推定が可能になる。
(2) データの統合
・スマートウォッチから取得した歩数や心拍データ、加速度データをスマホアプリと同期して、細かい姿勢判定に活用できる。
(3) 精度向上
・ウェアラブルは腕や足など人体により近い位置で計測し続けるため、加速度や姿勢変化をより正確に測定可能。
4-3. 実装の例
(1) 腕時計型デバイス + スマホ
・スマートウォッチの加速度データから「立位」と判定される動きを検知したら、Bluetooth等でスマホに通知。
・スマホ側アプリが受け取った時刻と連動して、「いつから立っているか」を計測し、座ったタイミング(=姿勢の変化を検知)で終了時刻を記録。
(2) 体重移動センサー(スマートシューズ) + スマホ
・足裏圧力が安定している場合を「立位」、不安定(分散が大きい)なら歩行や走行中、といった分類を行う。
・座位の場合は足への荷重が極端に減るため、閾値判定によって立位/座位を見分けやすい。
・スマホとはアプリやクラウド経由でデータを共有し、立っている合計時間を管理する。
4-4. 開発上の注意点
・ウェアラブルのバッテリー消費量を意識する:常にセンサーを高頻度でスキャンすると電池が早く切れる。
・高齢者が利用する場合、デバイスの装着が苦にならない設計が必要:腕時計タイプであれば普段から装着してもらえるが、足に何かつける場合は履き替えなどの煩雑さがないか考慮する。

5.まとめ
アイディアのポイント
(1) 基本は加速度センサーとジャイロセンサーが要
・スマホのみの場合はActivity Recognitionの利用や、スマホの傾き+静止判定を組み合わせて立位時間を推計。
(2) ウェアラブルを使うと精度・利便性が上がる
・腕時計型・足裏センサーなど、身体に近い場所で計測すると姿勢推定が簡単になり、アプリ側でのロジックも複雑になりすぎない。
(3) 利用者側の負担を減らす工夫
・特に高齢者向けでは、設定や充電、装着場所の固定など、ユーザーがミスしにくい仕組みづくりが重要。

以上のように、スマートフォン単体の場合でも加速度・ジャイロセンサーやOSのActivity Recognitionを活用すれば実現は可能です。しかし、利用者が毎回スマホをポケットや腰付近に装着してくれる前提がないと精度が低下することが多いです。その点、腕時計型ウェアラブルや足裏センサー等と連携することで、より精度の高い立位時間の計測や動作推定がしやすくなるでしょう。

 


図:立ちタイムのイメージポスター(DALL-E3による)


P. S. 灯台下暗し。隣のApple Watch ユーザによれば,Apple Watch はときどき「立ってね」とスタンドアップを促すそうだ。スタンドリマインダーというらしい。
「スタンドリマインダー」は、Apple Watchを装着している状態で1時間のうち最初の50分間座り続けている場合に「スタンドの時間です!」とメッセージ通知され、座り続けていることを予防する機能となっています。
Apple Watchでは1日の1時間当たり1分以上立っていた回数を測定しており、「アクティビティ」アプリの画面でその結果を確認することができます。(iPhone Wave から引用