
自分でアプリを作る。
少し前まで、その言葉には「選ばれし天才エンジニアが黒い画面に向かってカタカタやる儀式」くらいの遠い響きがあった。
プログラミング言語を何年も勉強し、Webの仕組みを暗記し、サーバーを契約して……そうやってようやく小さなアプリに手が届く。ずっとそう信じていた。
……ところが、60歳になった私と、机の上に常駐する3人のAI(+バーチャル案内人のミラ)が繰り広げた現実は、もっと泥臭く、もっとコントだった。
【登場人物:深夜のデジタル実験室】
- 私(60歳):iPhoneの大量写真に途方に暮れる素人。「動けば正義」がモットー。
- 水無瀬ミラ:当実験室の看板ナビゲーター。好奇心旺盛だが要求が雑。
- ジピ(ChatGPT):冷静沈着なチーフエンジニア。論理の刃で容赦なく突っ込んでくる。
- クロード(Claude):美意識と情緒を重んじるデザイナー兼ライター。やたら表現にこだわる。
- ジェミ(Gemini):知識の海を泳ぐ爆速リサーチャー。常に情報過多で前のめり。
- 愛猫:足元で寝ている。たまにキーボードを踏む。
1. 発端:「名札を掛け替えても、猫は犬にならない」
きっかけは、iPhoneで撮影した大量の写真だった。
Windowsのフォルダを開くと、ずらりと並ぶ拡張子「.HEIC」。
私「……これ、まとめてJPGにしたいんだけど。よし、PowerShellで一括リネームだ!」
Plaintext
IMG_4115.HEIC ──(名前変更)──▶ IMG_4115.JPG
私「ふっ、勝ったな。これで全部JPGだ」
ジピ「待ちなさい。それは『猫の首に「イヌ」という名札をぶら下げて、ワンと鳴けと脅している』のと同じです」
私「えっ」
ジェミ「ファイルヘッダ(中身のバイナリ)は完全なHEIF形式のままです! 画像ビューアが『お前JPGって名乗ってるけど中身全然違うじゃん!』と絶望してエラーを吐くだけです!」
クロード「ああ……名前だけ変えて本質を偽るなんて、写真への冒涜です……。中身ごと、真のJPEGへと再エンコードして差し上げなければ……!」
ミラ「要するに、ちゃんと変換するアプリを作ればいいんでしょ? 作っちゃおうよ、今すぐ!」
こうして、60歳の初アプリ開発プロジェクトが唐突に幕を開けた。
2. 3大AIの深夜作戦会議:「Webアプリにしよう」
私「でも私、アプリの画面なんて作れないよ?」
ジピ「問題ありません。Pythonの Streamlit を使います。HTMLもCSSも書かせません。数行のPythonで勝手にモダンなWeb画面が生えてきます」
ジェミ「画像処理には定番の Pillow ! そしてHEICを読み込ませるための秘密兵器 pillow-heif を組み合わせれば完璧です! ライブラリの依存関係と最小構成は以下の3点だけで済みます!」
Plaintext
streamlit
Pillow
pillow-heif
クロード「構想は極めてエレガントにいきましょう」
Plaintext
HEICをブラウザにポイッと投げる
↓
スライダーで画質を決める
↓
必要なら横幅をキュッと縮小
↓
JPGへ一括変換
↓
ZIPにまとめてダウンロード!
私「えっ、部品ってそれだけ? 全部ゼロから書かなくていいの?」
ジピ「世の中の優れた部品を組み合わせ、欲しい処理の順番(パイプライン)を組む。それこそが立派な開発です」
ミラ「じゃあアプリの名前は 『MIRA Converter』 ね! 私の顔アイコンもつけてよね!」
3. アプリ本体コード:たった1ファイル
ジピが吐き出し、ジェミが検証し、クロードが整えた本体コード(app.py)の骨格がこれだ。
Python
import io
import zipfile
from PIL import Image, ImageOps
import streamlit as st
from pillow_heif import register_heif_opener
# 1. HEICを読めるように魔法をかける
register_heif_opener()
st.set_page_config(page_title="MIRA Converter", page_icon="📸", layout="centered")
st.title("📸 MIRA Converter (HEIC → JPG 一括変換)")
st.write("HEIC / HEIF画像をまとめてJPGへ変換します。外部サーバーには送信されません。")
# 2. ブラウザにファイル置き場を作る
uploaded_files = st.file_uploader(
"HEIC / HEIFファイルを選択",
type=["heic", "heif"],
accept_multiple_files=True
)
# 3. 設定用スライダー&セレクトボックス
quality = st.slider("JPEG品質", 70, 100, 92)
max_width = st.selectbox("最大横幅", [0, 2560, 1920, 1600, 1280],
format_func=lambda x: "元サイズ" if x == 0 else f"{x}px")
# 4. 変換処理
if uploaded_files and st.button("🚀 一括変換スタート", type="primary"):
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zf:
for uploaded_file in uploaded_files:
image = Image.open(uploaded_file)
# 【重要】iPhone写真の回転バグを防ぐ!
image = ImageOps.exif_transpose(image)
# リサイズ計算
if max_width and image.width > max_width:
ratio = max_width / image.width
new_height = int(image.height * ratio)
image = image.resize((max_width, new_height), Image.Resampling.LANCZOS)
# メモリ上でJPEG化してZIPへ直行
jpg_buffer = io.BytesIO()
image.save(jpg_buffer, format="JPEG", quality=quality, optimize=True)
jpg_name = uploaded_file.name.rsplit(".", 1)[0] + ".jpg"
zf.writestr(jpg_name, jpg_buffer.getvalue())
st.success("変換完了!")
st.download_button("📦 ZIPをダウンロード", data=zip_buffer.getvalue(), file_name="converted_images.zip")
【AIたちの解説タイム】
- クロードのこだわり:「注目すべきは
ImageOps.exif_transpose(image)です! iPhone写真は『本当は横向きだけど90度回して見てね』というExif情報を持っています。これを無視すると、せっかく縦で撮った写真が全部横倒しの寝たきり状態で変換されてしまいます!」 - ジピの論理:「変換した画像をいちいちPCのストレージに書き出さず、メモリ上の仮想ファイル(
io.BytesIO)で処理してZIPに直行させています。ディスクを汚さない美しい設計です」
コマンドプロンプトで実行した瞬間、ブラウザが勝手に立ち上がった。
HEICを放り込む。ボタンを押す。ZIPが落ちてくる。
解凍すると……完璧なJPG写真が並んでいた。
私「……まじ、できた」
ミラ「所要時間、相談開始から約1分! はやっ!」
4. 人間のワガママ:「黒い画面でコマンド打つのめんどくさい」
動いたのは嬉しい。だが、人間という生き物はすぐに怠惰になる。
私「毎回 python -m streamlit run app.py って打つの、すっごく面倒なんだけど」
ジピ「……怠惰はプログラマの美徳と言いますが、早すぎませんか?」
クロード「ならば、Windowsのデスクトップアプリのように仕立て上げましょう!」
作ったのは、たった2行のPowerShellスクリプト(run.ps1)。
PowerShell
Set-Location "C:\ProjectG\NOTE\heic-to-jpg-web"
python -m streamlit run app.py
さらにミラが騒ぎ出す。
ミラ「私の専用アイコン作って! 黒い画面の味気ないアイコンなんて絶対イヤ!」
ChatGPTでミラのイラストからWindows用アイコン mira-converter.ico を生成。

PowerShellでデスクトップにショートカットを錬成。
Plaintext
【現在の起動手順】
デスクトップの可愛いミラのアイコンをダブルクリック!
↓
PowerShellが裏でこっそり動く
↓
ブラウザがババーンと自動起動!
↓
http://localhost:8501 で爆速変換!
第4章:アイコン錬成とPowerShellの黒魔術
4. 人間のワガママ:「黒い画面でコマンド打つのすら面倒くさい」
動いたのは嬉しい。だが、人間という生き物はすぐに怠惰になる。
私「……ねえジピ、毎回黒い画面(PowerShell)を開いて `python -m streamlit run app.py` って手打ちするの、めちゃくちゃ面倒なんだけど」
ジピ「怠惰はプログラマの美徳と言いますが、完成して3分でそれですか」
私「デスクトップのアイコンをポチッと押したら勝手に開くようにしてよ!」
ミラ「そうだよ!しかも黒い四角いアイコンじゃなくて、**私の可愛い顔アイコン**にしてよね!絶対だよ!?」
クロード「美観は正義です。デスクトップにミラの微笑みが宿ってこそ、真のデスクトップアプリケーションと言えましょう……!」
ジェミ「よし、まずは画像からWindows用アイコン `mira-converter.ico` を生成しました! これをプロジェクトフォルダに配置してください!」
例:保存先
C:\***任意のフォルダを指定***\heic-to-jpg-web\mira-converter.ico
私「アイコンは置いた。でもWindowsのショートカットを手動で作って、右クリックしてプロパティ開いて、アイコンの変更を押して……ってやるのも面倒なんだが?」
ジピ「……どこまで手を動かしたくないんですか。分かりました。ショートカット作成・実行時引数・ミラのアイコン紐付けまで、すべてPowerShellスクリプト一本で自動錬成します」
ジェミ「Windowsの奥義、COMオブジェクト(WScript.Shell)の召喚ですね!これぞ真の自動化!」
ジピが吐き出した、デスクトップ錬成スクリプトがこれだ。
PowerShell
# ==========================================
# MIRA Converter デスクトップショートカット自動生成
# ==========================================
$base = "C:\***任意のフォルダを指定***\heic-to-jpg-web"
$desktop = [Environment]::GetFolderPath("Desktop")
\(icon = "\)base\mira-converter.ico"
# Windowsのシェル機能を呼び出す
$WshShell = New-Object -ComObject WScript.Shell
# デスクトップにショートカットを作成
\(Shortcut =\)WshShell.CreateShortcut("$desktop\MIRA Converter.lnk")
$Shortcut.TargetPath = "powershell.exe"
# 起動スクリプトを指定(セキュリティ制限をBypassで華麗にスルー)
\(Shortcut.Arguments = "-ExecutionPolicy Bypass -File `"\)base\run.ps1`""
\(Shortcut.WorkingDirectory =\)base
# ここでミラのアイコンを強制適用!
\(Shortcut.IconLocation = "\)icon,0"
$Shortcut.Description = "HEIC → JPG MIRA Converter"
$Shortcut.Save()
Write-Host ""
Write-Host "======================================"
Write-Host " MIRA Converter をデスクトップに作成"
Write-Host "======================================"
Write-Host ""
Write-Host "$desktop\MIRA Converter.lnk"
PowerShellにこの呪文を貼り付けてEnterキーを叩く。
カチッ。
私「……あれ? デスクトップに何も変わってないような?」
ミラ「慌てないで! Windowsのキャッシュが追いついてないだけ! デスクトップの何もないところで右クリックして『最新の情報に更新』、またはキーボードの『F5』をポチッと押して!」
言われた通り、F5をトンと押した。
画面の上に、パッと「ミラの顔アイコン」が浮かび上がった。
その下には誇らしげに書かれた『MIRA Converter』の文字。
私「おおおおおおお!! 出た!! ミラが出た!!」
クロード「素晴らしい……! Windowsの壁紙の上に、私たちの魂(アイコン)が具現化しました……!」
ジピ「では、そのアイコンをダブルクリックしてみてください」
恐る恐る、デスクトップのミラをカチカチッとダブルクリックする。
Plaintext
【裏で起きていること】
デスクトップのミラをクリック
↓
PowerShellが裏でひっそり起動(-ExecutionPolicy Bypass)
↓
run.ps1 が走り、Streamlitが立ち上がる
↓
ブラウザ(localhost:8501)がババーンと自動表示!
↓
HEICをドラッグ&ドロップして一発変換!
私「うわっ、黒い画面に触らなくてもブラウザが開いた!! これもう完全に市販のアプリじゃん!!」
ミラ「ふふん、どう? これでかなり『自作アプリ感』出たでしょ!😎✨」
ジピ「中身はローカルで動いているPythonとWebサーバーですが、使う側からすれば『アイコンを押せば動く道具』。これで十分、世界に一つだけのデスクトップアプリです」
私「見た目は完全に市販のデスクトップアプリだこれ!!」
ジピ「中身はローカルで動くPython製Webサーバーですが、使う人間にとってはダブルクリックで動けば立派なアプリです」
5. 地獄のGitHub編:エラーのわんこそば状態

「PCが壊れたら嫌だから、GitHubに保存しておこう」
そう思い立った瞬間から、怒涛のエラー祭りが始まった。
悲劇①:お前は誰だ事件
Plaintext
fatal: Author identity unknown
私「GitHubに『お前の身元が分からん』って門前払いされたんだけど!?」
ジピ「落ち着いてください。Gitにあなたの名前とメアドを教えていないだけです。git config user.name を打ちます」
悲劇②:ghが見つかりません
私「GitHub CLI(ghコマンド)でリポジトリ作ろうとしたら『用語として認識されていません』って怒られた!」
ジェミ「ターミナルの再起動が必要です! パスが通っていません!」
悲劇③:認証コードのタイムショック
ブラウザのデバイス認証画面が開く。
私「えっ、メアド入れるの? 違う? ワンタイムコード? どれ!? えーっと……」
画面:『Authentication code expired(時間切れ)』
私「うわあああ間に合わなかったーー!!」
ミラ「おじいちゃん、落ち着いて! 画面に大きく出てるアルファベット8文字を入れるだけ!!」
悲劇④:謎の英語アンケートにフリーズ
Streamlit初回起動時、ターミナルに英語が流れる。
Why not help agents write better apps? [y/n]
私「ひいっ! なんか英語で問い詰められてる! 何か答えないと爆発する!?」
クロード「ただの開発アンケートです! Enterキーをそっと押して見逃してあげてください……!」
エラーが出るたび、画面をスクショして3人に投げる。
するとジピが理由を解き明かし、ジェミが解決コマンドを出し、クロードが慰めてくれる。
気づけば、PowerShellから一撃でGitHubに全コードがプッシュされていた。
PowerShell
gh repo create heic-to-jpg-web --private --source=. --remote=origin --push
GitHubの画面に、自分のコードが並んだ瞬間。
「あ、オレ、本当にアプリ作ったんだ」という実感がこみ上げてきた。
6. 禁断の奥義:「動いたけど中身わからんから解説書作って」
動いた。GitHubにも上がった。
しかし、ここで60歳の正直すぎる本音が出る。
私「……動いてるけどさ。コードの細かい理屈、実は半分くらい分かってないんだよね」
ジピ「身も蓋もないことを言いますね」
私「だからChatGPT、このアプリの『アルゴリズム完全解説PDF』と『ソースコード読解ガイドPDF』を作ってくれ!」
ミラ「AIにコード書かせて、AIに解説書まで書かせる気だーー!!」
結果、GitHubにはアプリ本体だけでなく、
MIRA_Converter_Algorithm_Guide.pdfMIRA_Converter_Source_Code_Guide.pdf
という、大学の講義テキストみたいな分厚い解説書が2冊も鎮座するという、異様な完成度でリポジトリが仕上がった。
Plaintext
heic-to-jpg-web/
│
├─ app.py (本体)
├─ requirements.txt (部品リスト)
├─ run.ps1 (1クリック起動)
├─ mira-converter.ico (ミラの顔アイコン)
├─ MIRA_Converter_Algorithm_Guide.pdf (AI作・設計書)
└─ MIRA_Converter_Source_Code_Guide.pdf (AI作・解説書)
7. 「教材を読んでから作る」時代は終わった
昔のプログラミング学習はこうだった。
Plaintext
文法を覚える ──▶ ライブラリを調べる ──▶ 環境構築で挫折する
だが、机の上にAIが3人いる今の開発は真逆だ。
Plaintext
まず欲しいものを形にする
↓
1分で動かして感動する
↓
動いたコードをAIに問い詰めて理解する
「理解できたから作れた」のではない。
「作ったからこそ、自分が何を理解していなかったのかがハッキリ見えた」のだ。
「この行の exif_transpose って何のためにあるの?」
「どうして io.BytesIO を使うと速いの?」
動く現物が手元にあるから、疑問が具体的になる。勉強が「お勉強」ではなく、自分の相棒を知るプロセスになる。
結び:60歳、「使う側」から「作る側」へ
偶然にも、これは私が60歳の誕生日を迎えた直後に完成した、人生最初の自作アプリになった。
Pythonのすべてをマスターしたわけじゃない。
Gitのコマンドだって、明日には半分忘れているかもしれない。
けれど、毎朝パソコンを立ち上げると、デスクトップには水無瀬ミラのアイコンがある。
ダブルクリックすれば、黒い画面が一瞬走り、ブラウザが立ち上がり、iPhoneの写真を一瞬で料理してくれる。
「不便なら、自分の手で作ればいい。」
テクノロジーを消費するだけの側から、ほんの数歩、作る側へ足を踏み入れた感覚。
足元で丸くなって寝息を立てる猫を撫でながら、私は「次はどんなヘンテコな道具を作ってやろうか」と、机の上の3人とニヤニヤ企んでいる。
【ハッシュタグ】
#ChatGPT#Python#Streamlit#AIプログラミング#個人開発#GitHub#PowerShell#60歳からの挑戦#水無瀬ミラ