Jewelry AI・モデルカタログ

1回の応答で、グリッド用の画像と拡大用の画像が用意されます

サーバーは、端末が何かを描画する前に、一覧に含まれるすべてのモデルを準備します。モデルごとに2つの画像アドレス、小さい画像がないモデルの代わりに使われる元のファイル、そして画像レコードを解決できないモデルの空のアドレスです。そのいずれもエラーにはなりません。だからこそ、見慣れないカードは画面だけからは判断しにくくなります。

1回の一覧要求で行われること

以下はすべて1回の応答の中で、端末がカードを描画する前に起こります。

  1. アプリがモデルの一覧を要求する

    カタログを開く、あるいは絞り込むと、1回の要求が生まれます。以下の手順は、その応答を準備する処理の一部です。

  2. 応答に含まれるすべてのモデルに、2つのアドレスが用意される

    モデルごとに、グリッドで使う小さい画像と、拡大に使うフルサイズの画像が、同じまとまりの中で用意されます(`const [thumbnailUrl, imageUrl] = await Promise.all([`、apps/api/src/models/models.service.ts)。

  3. 小さい画像がないモデルには、代わりに元のファイルが与えられる

    グリッドの枠は元のアセットにフォールバックします(`sign(m.thumbnailAssetId ?? m.assetId),`)。失敗するものはなく、モデルも一覧での位置を保ちます。違いは、このカードが大きいファイルを運ぶことだけです。

  4. 画像レコードが見つからないモデルも、位置を保つ

    モデルが取り除かれるのではなく、アドレスが空で返ります(`if (!id) return null;`)。空のアドレスが空白として描かれるのか、プレースホルダーになるのか、それ以外になるのかはアプリ側で決まっており、ここでは検証していません。

  5. モデルを開くときは、すでに届いているアドレスが使われる

    フルサイズのアドレスは同じ応答で用意されているため、大きい画像を見つけるためにアプリがサーバーへ問い合わせ直す必要はありません。

両方のサイズを一緒に用意する理由

まとめて処理するのは意図的で、その理由はコードに記録されています。

目的は、それを実行するコードの横にコメントとして書かれています。
コメントには、グリッド用の画像と拡大用の画像を1回でまとめて用意し、表示するカードごとにフル解像度のファイルを端末がダウンロードしないようにする、と述べられています(apps/api/src/models/models.service.ts)。そのコメントに現れる数値は、書かれた時点の状況を説明するものであり、コードが読み取ったり適用したりする上限ではありません。
モデルを開くかどうかに関わらず、両方のアドレスが用意されます。
この組は応答に含まれるすべてのモデルについて作られるため、準備はカードを開いた時点ではなく、一覧に対して一度だけ行われます。
代替は、それが当てはまるモデルに限られます。
元のファイルがグリッドに使われるのは、専用の小さい画像を持たないモデルだけです。同じ応答に含まれるほかのモデルは、グリッドには小さい画像が、拡大には元のファイルが与えられます。

返ってくるもの、そして保存できないもの

応答に含まれるモデルごとに、2つのものが返ります。グリッドが描画する画像のアドレスと、フルサイズ表示が開く画像のアドレスです。モデルが専用の小さい画像を持たない場合、この2つは同じ元のファイルを指すことがあります。また、背後の画像レコードを解決できない場合、アドレスは空で届きます。どちらの場合も、モデル自体が一覧から外されることはありません。

これらのアドレスは、それを要求した一覧の要求のために生成されます。したがってモデル画像のアドレスは、保存して再利用するものではありません。用意されたアドレスがどれくらいの間使えるのかは、このページでは検証していません。

以上のどれも決めていないのは、空のアドレスを受け取ったあとにアプリが何をするかです。サーバーはアドレスを空にしたままモデルを返します。空白を描くのか、プレースホルダーを置くのか、それ以外にするのかはモバイル側の判断であり、ここで調べた範囲の外にあります。

見えているものと、サーバーが行ったこと

3つの見え方と、それぞれの背後にあるサーバー側の動作です。

グリッドに現れるものサーバーが行ったことそれが確立しないこと
画像のないカード画像レコードを解決できなかったため、モデルを応答に残したまま、画像アドレスを空で返したそのモデルがカタログから取り下げられたこと、あるいは端末でダウンロードが失敗したこと
隣のカードより明らかに重いカードそのモデルには専用の小さい画像がないため、グリッドの枠をモデルの元のファイルで埋めた画像が壊れていること、あるいは要求が何らかの形で失敗したこと
待たされずに開くフルサイズ表示フルサイズのアドレスを、グリッド用のアドレスと同じ応答で用意したサーバーが2回目の要求に速く答えたこと、あるいはアプリが何を保存しているかが検証されたこと

空のカードや重いカードが証明しないこと

以下は画面だけを見れば無理のない結論ですが、その背後のコードに照らすと誤りです。

  • 空のカードを、インストールの破損や接続の切断として読む。

    空のアドレスは、端末に何かが届く前にサーバー側で生まれます。再インストールや接続のやり直しは、関与していない層に働きかけることになります。

  • グリッド全体がフル解像度の画像をダウンロードしていると結論づける。

    元のファイルから配信されるのは、専用の小さい画像を持たないモデルだけです。両方のサイズを1回でまとめて用意するのは、それがすべてのカードに当てはまらないようにするためです。

  • 拡大のたびに、新しい要求がサーバーへ送られると想定する。

    フルサイズのアドレスはすでに一覧の応答に含まれているため、画像の場所を知るための追加の呼び出しは不要です。大きい画像を描画する際にアプリが何を転送するかは、ここでは調べていません。

  • 2つのモデルを、カードが現れる速さで比べ、一方の写真が劣ると判断する。

    その違いは、グリッドの枠にどのファイルが用意されたかによるものであり、背後にある写真の品質によるものではありません。

モデル画像の欠落を報告する前に

このページが扱う場合と扱わない場合を切り分ける5つの観察。

  • カードは存在して画像がないのか、モデルがグリッドから欠けているのかを確かめる。ここで説明しているのは前者だけ。
  • 同じグリッドのほかのカードが画像を表示しているかを確認する。各モデルのアドレスは、1回の応答の中で個別に用意されるため。
  • 画像ではなくモデルを控える。空のアドレスはそのモデルの画像レコードに従い、応答がサーバーを出る前に生まれる。
  • モデルを一度開く。フルサイズ表示が待たされずに現れるなら、そのアドレスは要求時ではなく、グリッドと一緒に届いている。
  • 画像が欠けているのはカード上か、フルサイズ表示か、その両方かを控える。グリッド用のアドレスとフルサイズのアドレスは、レコードの別々の項目から用意される。

このページが扱わないこと

読んだコードは一覧の経路のみを対象としており、画面までは及びません。

  • 用意されたアドレスがどれくらいの間使えるか。検証できたのは、アドレスが一覧の要求ごとに生成されるということだけです。
  • 空のアドレスが端末上でどう描画されるか。それはモバイル側で決まっており、検証していません。
  • カタログにモデルが何件あるか。まとめて処理するコードの近くにある数値はコメントであり、コードが適用したり読み取ったりする値ではありません。
  • モデル画像がどこに保存されているか、またどのようなアクセス方針で配信されているか。
  • モデルのレコードと画像が、どのように作成、アップロード、編集されるか。調べたのは読み取りの経路だけです。
  • 生成が実行されたあとに、モデルがどのように使われ、検証され、あるいは拒否されるか。その処理はAPIの別の場所にあります。

よくある質問

あるモデルカードに画像が表示されないのは、なぜですか?

サーバーがそのモデルの画像レコードを解決できず、モデルを一覧から取り除く代わりに、画像アドレスを空にして返したためです(apps/api/src/models/models.service.ts)。その空間にアプリが何を描画するかは、このページでは検証していません。

モデル画像を拡大すると、サーバーへ別の要求が送られますか?

画像の場所を知るための追加の呼び出しは不要です。フルサイズのアドレスはグリッド用のアドレスと同じ応答で用意されるため、モデルを開く時点でアプリはすでにそれを持っています。

1枚のカードだけ、ほかより遅かったり重かったりするのは、なぜですか?

専用の小さい画像を持たないモデルは、グリッドの枠が元のファイルで埋められます。そのためそのカードだけがフル解像度の画像を運び、ほかのカードは小さい画像を運びます。失敗するものはなく、モデルは一覧での位置を保ちます。

カタログのすべてのモデルに、専用の小さい画像がありますか?

必ずしもそうではありません。小さい画像がない場合にグリッドへ元のファイルを使うことで、コードはその状況に対応しています。どのモデルがその状態にあるかはカタログのデータであり、このページの背後にあるコードからは読み取れません。