Fleeexdocs

Vision

Envoyez des images sous forme de parties de contenu : URI data: uniquement, 8 au maximum par requête, sur un message user, et voici comment une image est réservée.

Le content d'un message peut être un tableau de parties au lieu d'une chaîne : { type: "text", text } et { type: "image_url", image_url: { url } }. La forme en chaîne simple reste inchangée.

describe.ts
import { readFile } from "node:fs/promises";
 
const bytes = await readFile("./receipt.png");
const dataUri = `data:image/png;base64,${bytes.toString("base64")}`;
 
const completion = await client.chat.completions.create({
  model: "nova-lite",
  messages: [
    {
      role: "user", // les images ne sont permises que sur un message user
      content: [
        { type: "text", text: "Quel est le total sur ce reçu ?" },
        { type: "image_url", image_url: { url: dataUri } },
      ],
    },
  ],
});

Les parties sont transmises dans l'ordre où vous les avez envoyées. C'est cet ordre que voit le modèle : le normaliser (tout le texte, puis toutes les images) changerait la réponse.

URI data: uniquement

Une URL http(s) distante donne un 400, et le message indique quoi envoyer à la place. C'est un refus délibéré et non un manque : l'entrée image du fournisseur est constituée d'octets bruts, jamais d'une URL. L'honorer supposerait que Fleeex aille la chercher côté serveur, de façon synchrone, sur le chemin de facturation. Cela ouvrirait une surface de falsification de requête côté serveur dans un processus qui détient des identifiants cloud, plus un téléchargement sans borne et une latence sans borne devant un appel de modèle payant, pendant qu'une réservation est gelée sur le portefeuille.

// 400 : fleeex ne va pas chercher d'URL distante
{ type: "image_url", image_url: { url: "https://example.com/cat.png" } }
 
// correct
{ type: "image_url", image_url: { url: "data:image/png;base64,iVBORw0KGgo…" } }

Récupérez-la vous-même, dans votre propre processus, et intégrez les octets.

Formats

png, jpeg (jpg est accepté comme alias, car c'est ce qu'envoient les vrais clients), gif, webp.

Le type de média déclaré est confronté aux octets de signature de la charge utile. Une divergence donne un 400, parce que le fournisseur refuserait de toute façon une image mal étiquetée (un 502 pour quelque chose qui peut être nommé), et parce que Fleeex ne transmettra pas autre chose que ce que vous avez déclaré.

Une URI data: malformée donne un 400, jamais un 502 : le base64 est confronté à l'alphabet standard, avec le bon remplissage, avant d'être décodé, si bien que des octets approximatifs ne sont jamais transmis comme s'ils étaient ceux que vous aviez envoyés.

detail uniquement à auto

image_url.detail est accepté à 'auto' (la valeur par défaut d'OpenAI, purement décorative) et donne un 400 à low ou high. Ces valeurs sélectionnent une autre tokenisation de l'image côté OpenAI : elles changeraient donc à la fois la réponse et les tokens facturés, et le fournisseur n'a pas de réglage équivalent.

Limites

Limite
Images8 au maximum par requête, car c'est le niveau auquel la réservation est dimensionnée
Parties de contenu20 au maximum par message
Chaque imagese décode en 1 octet…512 Ko
Oùuniquement sur un message user

Le fournisseur n'accepte un bloc image que dans un tour utilisateur : un prompt système n'a pas de bloc image du tout, et un tour assistant est la sortie du modèle lui-même. Les deux sont refusés ici, si bien que le refus du fournisseur n'arrive jamais.

En pratique, le plafond de 1 Mo sur le corps de la requête mord généralement avant la limite par image, puisque 8 × 512 Ko le dépasse largement. Les deux s'appliquent.

Une image est réservée à un plafond forfaitaire et pessimiste

Bon à savoir avant d'en envoyer huit : la réservation d'une image est un plafond forfaitaire par image, délibérément sans rapport avec sa taille en octets.

En effet, le coût en tokens d'une image suit ses dimensions, et non la taille de son encodage compressé. Un JPEG de 40 Ko peut faire 8 mégapixels ; un PNG de 400 Ko peut être une petite icône. Tarifer le base64 comme du texte sous-réserverait gravement une petite image densément codée, et tarifer 512 Ko au tarif du texte mettrait un 402 sur toute requête légitime. Chaque image ajoute donc à la réservation un nombre fixe de tokens d'entrée, calculé au pire cas.

Deux conséquences :

  • Vous pouvez recevoir un 402 sur un portefeuille qui aurait couvert la facturation réelle. La réservation est un plafond, et une requête portant plusieurs images réserve d'emblée quelques dizaines de milliers de tokens d'entrée.
  • Vous restez facturé sur la mesure. La facturation vient de la consommation rapportée par le fournisseur, et la part inutilisée de la réservation est libérée au règlement de l'appel. Réserver large ne vous coûte rien d'autre que le temps pendant lequel les fonds sont immobilisés.

Fleeex n'analyse pas les dimensions en pixels : une image au-delà de la limite de résolution du fournisseur est donc refusée par celui-ci (un 502) plutôt que nommée dans un 400. Des images très compressées peuvent la dépasser en tenant sous 512 Ko.

Ce qui est stocké

Rien. Les octets d'image sont du contenu de prompt : jamais journalisés, jamais stockés, et jamais renvoyés en écho dans un message d'erreur.