AIでワイン管理ツールを作るとどこまでできるか
生成AIにコードを書かせる方法は、既製アプリと表計算の間を埋めます。エクセルでは面倒な自動判定を入れられて、既製アプリでは足せない列を足せる。まず、実際に何ができあがるのかを示します。
実際に作ったツールの画面構成
完成物の仕様を先に決める
作り始める前に、何を持つツールなのかを決めます。ここが決まっていないと、生成AIは一般的な在庫管理ツールを出してきて、ワインで必要な列が入りません。
実際に作ったものは、9項目の入力と4つの集計、飲み頃の自動判定、絞り込み、CSV書き出しという構成です。ワインで外せないのは2つ。飲み頃を開始年と終了年に分けて持つことと、棚位置の列を持つこと。どちらも一般的な在庫管理ツールの作例には入っていません。
動作確認では、5銘柄9本を登録した状態で、今が飲み頃7本・飲み頃を過ぎた1本・購入価格の合計50,100円が正しく計算されました。2028年から飲み頃のバローロは「寝かせる」、2025年で終わるボジョレーは「過ぎた」と自動で判定されます。
かかる時間と必要なもの
必要なのは生成AIとテキストエディタとブラウザだけです。Windowsならメモ帳、macOSならテキストエディットで足ります。サーバーもデータベースも要りません。
作業時間は、プロンプトを書くのに10分、出力を保存して開くのに1分、触って直したい点を伝え直すのに20分ほど。最初の1回で完成させようとせず、動かしてから直す前提で進めたほうが結局は早く終わります。
生成AIに渡すプロンプトを組み立てる
出力の質は、渡す要件の具体度でほぼ決まります。「ワイン管理ツールを作って」だけでは、列も判定も一般的なものになります。
プロンプトに必ず含める4要素
出力形式を先に縛る
最初に指定すべきは形式です。ここを空けておくと、ReactやNode.jsを前提にした構成が返ってきて、動かすまでにインストール作業が発生します。
「HTMLファイル1枚で完結」「外部ライブラリを使わない」「ダブルクリックで開けること」の3つを書くと、貼り付けて保存するだけで動くものが返ってきます。プログラミングの知識がないなら、この指定の有無で難易度がまるで違います。
そのまま使えるプロンプト
以下は、後述する3か所の修正を反映させた完成版のプロンプトです。最初からここまで書けていたわけではなく、一度動かしてから足しています。銘柄の例や列は自分の運用に合わせて差し替えてください。
自宅のワインを管理するツールを作ってください。
【出力形式】
- HTMLファイル1枚で完結させる(CSSとJavaScriptも同じファイルに入れる)
- 外部ライブラリやCDNは使わない
- ファイルをダブルクリックしてブラウザで開くだけで動くこと
【持たせる列】
銘柄/生産者/ヴィンテージ(年)/タイプ(赤・白・ロゼ・スパークリング・その他)/
本数/棚位置/飲み頃の開始年/飲み頃の終了年/購入価格
【自動でやってほしいこと】
- 今年が「飲み頃の開始年〜終了年」の範囲に入っている行は背景色を変える
- 終了年が今年より前の行はグレーにして「過ぎた」と表示する
- 開始年が今年より後の行は「寝かせる」と表示する
- 画面上部に「登録本数」「今が飲み頃の本数」「飲み頃を過ぎた本数」
「購入価格の合計」を数字で表示する
【操作】
- 銘柄・生産者での絞り込み検索
- タイプでの絞り込み
- 行の削除
- CSVでの書き出し(Excelで開いても文字化けしないようにする)
【保存方法】
- localStorage に保存し、ブラウザを閉じても消えないようにする
【表示】
- スマートフォンの幅では表が横スクロールしないよう、
1行を縦積みのカードに組み替える
- 日本語で表示する
最後の「横スクロールしない」は省かないでください。列が9つあるので、指定しないとスマートフォンで表がはみ出し、実際には使えないものができあがります。
出力を保存して開く
返ってきたコードをすべて選択してコピーし、テキストエディタに貼り付けます。保存するときのファイル名は wine.html のように、拡張子を必ず .html にします。メモ帳の場合は、保存時のファイルの種類を「すべてのファイル」に変えないと wine.html.txt になり、開いてもコードがそのまま表示されます。
保存したファイルをダブルクリックすると、既定のブラウザで開いて動きます。
実際に動かして直した3か所
最初の出力がそのまま使えることは少なく、触ってみて分かる問題が出ます。実際に直したのは次の3か所でした。
飲み頃を「範囲」で持たせる
最初の出力では、飲み頃が「2028年」のような1つの年で返ってきました。これだと「まだ早い」は判定できても「もう過ぎた」が判定できません。開始年と終了年の2つに分けるよう指示し直しています。
範囲で持たせると、判定は今年と比べるだけで済みます。
const thisYear = new Date().getFullYear();
function status(r){
const f = Number(r.from), t = Number(r.to);
if (!f && !t) return { cls:'', label:'—' };
if (t && thisYear > t) return { cls:'past', label:'過ぎた' };
if (f && thisYear < f) return { cls:'', label:'寝かせる' };
return { cls:'ready', label:'今が飲み頃' };
}
この関数が返す cls をそのまま行のクラス名に使えば、色分けと文言が1か所で決まります。年が明ければ自動で判定し直されるので、手で見直す作業は発生しません。
棚位置を座標で持たせる
棚位置は自由入力にすると「上のほう」「奥」といった書き方が混ざり、あとで探せません。2-05 のように「段-列」で書くと決め、入力欄のプレースホルダにその形式を出すようにしました。
段は上から、列は左から数える、と決めておけば、家族が見ても同じ場所を指せます。エクセルで同じことをする場合の考え方は「ワインの在庫管理をエクセルで作る方法|列の設計と限界」で扱っています。
スマートフォンで表を崩さない
9列の表はスマートフォンの幅に収まりません。最初の出力は横スクロールで逃がす作りでしたが、片手で操作すると使いにくい。狭い幅では1行を縦積みのカードに組み替えるよう指示し直しました。
@media (max-width:760px) {
table, thead, tbody, tr, td { display:block; width:100%; }
thead { display:none; }
tr { border-bottom:1px solid #e3e1dd; padding:10px 12px; }
td { border:0; padding:3px 0; display:flex; gap:10px; }
td::before { content:attr(data-l); flex:0 0 84px; color:#7a726b; font-size:11px; }
}
各セルに data-l="銘柄" のようなラベルを持たせておき、狭い幅ではそれを見出しとして表示します。横に流すのではなく、縦に積み替える。列数の多い表をスマートフォンで扱うときの定石です。
自作ツールの限界
作ってみると、できないことがはっきりします。ここは工夫で埋まる部分ではなく、構造上の制約です。
自作ツールで越えられない3つの壁
他の端末・他の人と共有できない
これが最大の制約です。保存先のlocalStorageについて、MDNはそのドキュメントのオリジンにひもづくストレージで、格納されたデータはブラウザーのセッションを跨いで保存されると説明しています。裏返せば、保存されるのはその端末のそのブラウザの中だけ。
自宅のパソコンで登録したワインは、買い物中のスマートフォンからは見えません。家族と共有することもできません。共有しようとすると、サーバーとデータベースとログインの仕組みが必要になり、作る対象が「HTMLファイル1枚」ではなくなります。
格納されたデータは、ブラウザーのセッションを跨いで保存されます。
localStorage は window プロパティの読み取り専用プロパティで、この Document の origin における Storage オブジェクトにアクセスできます。/格納されたデータは、ブラウザーのセッションを跨いで保存されます。 — localStorage の定義とデータ保持についての記述より
ブラウザのデータを消すと消える
localStorageのデータには期限がなく、ブラウザを閉じても残ります。ただしこれは「消えない」という意味ではありません。MDNは、プライベートブラウジングやプライバシーモードで読み込んだ文書のlocalStorageは、最後のプライベートタブを閉じた時点でクリアされると説明しています。通常のウィンドウで使っていても、ブラウザ側でサイトデータを削除する操作をすれば保存先ごと失われます。
対策はCSV書き出しを定期的に実行して手元に残すこと。それだけです。自動バックアップの仕組みは、共有と同じくサーバー側が必要になります。数十本なら、月に一度書き出しておく程度で足ります。
localStorage は sessionStorage によく似ていますが、 localStorage のデータには期限がないのに対し、 sessionStorage のデータはページセッションが終了したとき、すなわちページが閉じられたときにクリアされます。
localStorage は sessionStorage によく似ていますが、 localStorage のデータには期限がないのに対し、 sessionStorage のデータはページセッションが終了したとき、すなわちページが閉じられたときにクリアされます。/「プライベートブラウジング」や「プライバシーモード」のセッションに読み込まれた文書の localStorage のデータは、最後の「プライベート」タブが閉じられたときにクリアされます。 — 前者は sessionStorage との違い(データの保持期間)、後者はプライベートブラウジング時の扱いの説明より
ラベル撮影での自動入力は作れない
入力の手間を減らしたいと考えると、ラベル撮影による自動入力に行き着きます。しかしHTMLファイル1枚・外部サービスなしという本記事の前提では作れません。画像から文字を読むところまではできても、読んだ内容を実在のワインと突き合わせる仕組みが手元に無いためです。
winecodeは、ラベルが傷んでいたり見切れている場合でも生成AIが推測して読み込むと説明しています。欠けた情報を補って埋める処理まで含むので、自作ツールの延長線上にはありません。手入力を前提に、入力欄の数を絞る方向で設計するほうが無理がないと思います。AI読み取りの仕組みと精度の考え方は「ワインラベルのAI読み取りはどこまで正確か|仕組みと限界」で扱っています。
ラベルが傷んでいたり、見切れたりしている場合でも、生成AIが推測することにより、高い精度で読み込みを行うことができます
ラベルが傷んでいたり、見切れたりしている場合でも、生成AIが推測することにより、高い精度で読み込みを行うことができます — ラベル自動認識機能の説明より
自作と既製アプリの使い分け
どちらが優れているという話ではなく、成立する条件が違います。判断の目安を整理します。
自作が向く場合/既製アプリが向く場合
自作の強みは、列と判定ルールを完全に自分で決められることです。「このワインは誰と飲んだか」のような、既製アプリにない列も好きに足せます。生成AIに追加を書かせれば数分で反映されます。
ただし共有が必要になった時点で、自作の前提は崩れます。ワイン在庫管理アプリのShelvinは、QRコードを相手に提示するだけでセラー情報を共有でき、無料で16本まで登録できます。ラベル撮影による自動入力も、無料プランで週2回まで使えます。
QRコード招待:専用のQRコードを相手に提示するだけで、簡単に登録してワインセラー情報を共有できます。
QRコード招待:専用のQRコードを相手に提示するだけで、簡単に登録してワインセラー情報を共有できます。 — 共有・招待機能の説明より
Free ¥0 16本まで登録可能 ラベルスキャン(週2回まで) セラー位置管理機能 広告表示あり — 「料金プラン」Free プランの掲載項目より
まとめ
生成AIにHTMLファイル1枚を書かせる方法なら、ワイン管理ツールは数十分で手に入ります。プロンプトで決めるのは、出力形式・持たせる列・自動判定・保存方法の4つです。とくに飲み頃を開始年と終了年の範囲で持たせる指定と、スマートフォンで横スクロールさせない指定は、入れておかないと使えないものができあがります。
実際に作って直したのは3か所でした。飲み頃を1つの年ではなく範囲にすること、棚位置を「段-列」の座標に固定すること、狭い幅では表を縦積みのカードに組み替えること。いずれも触ってみて初めて分かる部分です。
越えられないのは、共有・消失・ラベル撮影の3つです。データは端末のブラウザの中だけに保存されるため、別の端末からも家族からも見られません。ブラウザの閲覧データを消せば一緒に消えます。この3つが要らないなら自作で十分ですし、どれか1つでも要るなら、そこから先は自作の対象がツールではなくサーバーに変わります。
共有と撮影登録まで含めて試すなら、無料枠で16本まで登録できて位置管理も使える Shelvin(App Store) を、自作ツールと並べて比べてみると判断しやすくなります。


