アダルト写真加工フィルターをアプリに組み込む方法
アダルト写真加工フィルターをプロダクトに組み込む作業は、一見すると画像処理の課題に見えますが、実際には配管工事のような課題です。モデルの処理そのものは API 呼び出し 1 回で買えてしまいます。スプリントを食いつぶすのはその周辺、つまりタイムアウトするアップロード、誰も見ていない間に完了するジョブ、こっそり二重課金を招くリトライ、そして「結果はどこへ行ったのか」というサポート問い合わせです。本ガイドでは連携作業を最初から最後までたどり、チームが必ずと言っていいほど時間を失う箇所を指摘します。
この連携が実際に何で構成されるのか
写真変換 API は本質的に非同期です。生成には時間がかかるため、その間 HTTP 接続を開いたままにしておくのは悪手です。モバイル回線は切れますし、ロードバランサーはアイドル接続を切断し、自分自身のリクエストタイムアウトが足を引っ張り始めます。そのため構造はいつも同じで、処理を投入し、識別子を受け取り、後から結果を回収します。
- 写真と使用したいプリセットを送信し、ジョブ識別子を受け取ります。
- ポーリング、またはイベント購読でジョブの状態を追跡します。
- ジョブが成功を報告したら、完成した画像を取得します。
- 失敗時とリトライの経路を実装します。実際の作業量の大半はここにあります。
ステップ 1: ジョブの投入
投入は multipart リクエストで、画像、プリセット識別子、そしてその写真を処理する権利と同意を得ているという確認を含みます。あわせて冪等キーを送ってください。このヘッダー 1 つの有無が、きれいな連携とサポート案件の分かれ目になりますし、追加コストはゼロです。
curl -X POST https://api.example/api/v1/jobs \ -H "X-API-Key: $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -F image=@photo.jpg \ -F feature=bikini \ -F consent=confirmed
レスポンスにはジョブ識別子と初期ステータスが含まれます。他の何よりも先に、その識別子を自社のユーザーまたはセッションのレコードに紐づけて即座に永続化してください。次の瞬間にプロセスが落ちたとしても、そのレコードだけが処理を再び見つける手がかりになります。
ステップ 2: 進捗の追跡
ジョブを追う方法は 2 つあり、成熟した連携では両方を使います。WebSocket 接続はステータス変化と進捗をリアルタイムに届けてくれるので、画面のプログレスバーを動かすのに向いています。ジョブエンドポイントへのポーリングは、システムを「快適」ではなく「正しい」ものにするフォールバックです。ソケットは切れますし、スマートフォンはスリープしますが、数秒に一度のポーリングのコストはほぼゼロです。
WebSocket は最適化、ポーリングは信頼できる情報源と位置づけてください。これを逆にしたチームは、サーバー側では問題なく完了しているのにクライアント側では永遠に止まって見えるジョブを抱えることになります。肝心なイベントが、ソケットの再接続中に届いてしまったからです。
ステップ 3: 結果の受け取り
ジョブが成功を報告すると、出力の一覧が含まれます。各出力はそのジョブを作成したのと同じ API キーで取得するため、結果が公開アドレスに置かれることはなく、URL から推測されることもありません。後から表示する必要があるプロダクトなら、受信時に自社ストレージへ画像をダウンロードしてください。画像 API は処理サービスであってフォトライブラリではなく、結果は無期限には保持されません。
ステップ 4: 失敗、リトライ、二重課金の罠
厄介なのは API がエラーを返す失敗ではありません。曖昧な失敗のほうです。リクエストは送信されたが通信が切れ、ジョブが作成されたかどうか分からないという状況です。ここで素朴にリトライすると、料金を二度払い、1 回のユーザー操作に対して結果が 2 つできてしまいます。
これを解決するのが冪等キーです。同じキーで再送すれば、リトライが何回発火しても新規ジョブではなく元のジョブが返ります。キーはユーザー操作が発生した時点で生成し、ジョブレコードとともに保存し、その同じ操作のすべてのリトライで再利用してください。試行ごとに新しいキーを作ってしまうと、この仕組み自体が無意味になります。
連携が滞りやすいポイント
- アップロードの検証をクライアント側だけで行うこと。API 呼び出しを消費する前に、拡張子ではなく中身でサーバー側チェックを行ってください。
- 全体を同期処理で作り込んでから、モバイルクライアントが生成完了のはるか手前で接続を切ることに気づくこと。
- WebSocket を唯一の進捗チャネルとして扱い、ポーリングのフォールバックを用意しないこと。
- ローカルに何も保存せず、再起動でユーザーと実行中ジョブの対応関係を失うこと。
- 結果が一時的なものであることを忘れ、API を永続ストレージとして期待すること。
妥当な作業順序
アプリケーションのコードを書く前に、まず curl で写真 1 枚を全経路 (投入、ポーリング、ダウンロード) に通してください。次に同じ 4 回の呼び出しを、永続化とともにバックエンドへ組み込みます。WebSocket は最後に、すでにそれなしで動くシステムの上にプログレスバーの改善として載せるだけにします。この順番なら連携は 1 日で終わりますが、逆順にすると 2 週間のデバッグになります。
よくある質問
1 回のリクエストにはどれくらい時間がかかりますか。
生成は非同期で、バックグラウンドで完了します。ブロッキング呼び出しではなく進捗表示を前提に画面を設計すれば、所要時間の長短はアーキテクチャ上の問題ではなくなります。
API を使うには WebSocket が必要ですか。
いいえ。すべて REST だけで動作します。WebSocket は進捗をリアルタイムに感じさせるためのものであり、ジョブエンドポイントへのポーリングでも同じ情報が得られます。
同じリクエストを 2 回送るとどうなりますか。
同じ冪等キーであれば元のジョブが返り、2 回目の生成も課金も発生しません。
uncloth.app で開発する
REST エンドポイント 1 本、11 種類のプリセット、結果はそのままお客様のバックエンドへ返却されます。開発中のプロダクトについてお知らせいただければ、アクセス情報をお送りします。
アクセスを申請する