顔写真を扱う Web サービスは、解析そのものより先に「原図がどこに残るか」で詰まりやすい。公開結果 URL、アプリログ、学習データ、メール添付。どれか一つでも残すと、あとから消す設計に作り直す方が高い。
ここでは、無料の顔写真解析をログインなしで出す前提で、サーバーに原図を置かないために実際に並べた順を書く。同じ制約(同意、一時保存、削除の再試行)を後から足す人向けの手順メモ。
先に固定した制約
実装の前に、落とさない約束を先に書いた。
- 送信前に、写っている人が 18 歳以上であることと、その写真を使ってよい許可があることを確認する
- 無料経路はアカウントもメールも要求しない
- 無料結果に公開 URL を付けない
- 解析が終わったら derivative の削除をすぐ試み、失敗分は後追いで掃除する
- アップロードした写真をモデル学習に使わない設定にする
「あとで消します」と書いて原図の File をそのまま POST すると、位置情報や機種、撮影時刻が入った EXIF までサーバーに乗る。削除より先に、ブラウザで derivative を作る。
1. ブラウザで描き直す
送るのは原図ではなく、キャンバスに描き直した JPEG だけ。createImageBitmap → canvas.drawImage → toBlob すると、EXIF はコピーされない。長辺は 1600px、JPEG quality は 0.86。サーバーが受け取るファイル名は portrait.jpg。
export async function preprocessPhoto(file) {
const bitmap = await createImageBitmap(file)
const scale = Math.min(1, 1600 / Math.max(bitmap.width, bitmap.height))
const canvas = document.createElement('canvas')
canvas.width = Math.max(1, Math.round(bitmap.width * scale))
canvas.height = Math.max(1, Math.round(bitmap.height * scale))
const context = canvas.getContext('2d', { alpha: false })
context.drawImage(bitmap, 0, 0, canvas.width, canvas.height)
bitmap.close()
const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/jpeg', 0.86))
return new File([blob], 'portrait.jpg', { type: 'image/jpeg' })
}
ブラウザの FaceDetector があれば、顔がゼロ/複数、という警告にだけ使う。アップロードの門にはしていない。未対応のブラウザを落とす理由がない。
明るさやボケの雑なチェックも、縮小キャンバスの輝度でやる。ゲートではなく、「この写真だと寸評が雑になる」と先に伝えるため。
2. 同意と乱用対策を、画像より前に置く
derivative を作ったあと、送信の直前に 18+ と許可の確認を取る。Cloudflare Turnstile とレート制限は IP やブラウザ情報を見るので、肖像そのものより先に置く。解析結果の非公開ページでは、公開アナリティクスを載せない。
ここまででサーバーに届くのは、メタデータのない JPEG と、解析に必要な短い指示だけ。
3. サーバーは中継して、すぐ消す
ブラウザから来た derivative は、安全確認と解析のためだけに一時保存する。モデル呼び出しはサーバー間。終わったら削除を試みる。失敗分は定期ジョブで再試行する。
無料結果は公開ページにしない。有料レポートだけ、推測しにくいリンクの裏に約 30 日置く。入力写真は生成後に消す。
プロバイダ側の保持は相手の規約に依存する、とはっきり書く。自前ストレージを空にしても、モデル API の側までゼロ秒とは言えない。
同じ経路を本番に載せた例
この順を、顔写真の「写り」フィードバックに使っている。
無料は 1 枚、アカウントなし。返ってくるのは Photo Appeal Score と、表情・光・構図・スタイリングの寸評。人の価値や科学的な美の順位ではない。同じ人でも写真が違えば結果は変わる、という前提で作っている。
まだ言えないこと
- インターネット上のサービスに、完全なセキュリティは言えない
- プロバイダ内部の保持まで自前では制御できない
- 削除は「試みる」。リトライがある、ということは失敗しうる
- これは美の判定器ではない
肖像を扱うなら、公開 URL を先に設計しない方が楽だった。消す経路を後付けすると、メール、CDN、解析ログのどこかに必ず残る。
制約の根拠(スコアの根拠ではない):
- Todorov and Porter (2014) — 同じ人でも写真が違えば第一印象が変わる
- Jenkins et al. (2011) — 日常写真の中での within-person のばらつき