# Describe objetos de una imagen con MandAPI

Envía una imagen local a un modelo con Vision mediante Chat Completions.

## Elige un modelo compatible con Vision

Los metadatos públicos actuales de MandAPI marcan varios modelos habilitados con **Vision**. Elige un identificador exacto disponible para tu cuenta en el [catálogo actual](/es/pricing). Sustituye `MODEL_ID` por ese ID; no uses un modelo solo de texto.

Esta receta se ha revisado contra los metadatos y el procesamiento local de solicitudes. No se ha ejecutado inferencia real de imágenes para esta guía. Las descripciones pueden contener incertidumbre; no representan mediciones garantizadas ni una evaluación de detección.

## Guarda un script pequeño

Utiliza Python 3.10 o posterior y guarda lo siguiente como `vision.py`. La clave permanece en el entorno. La imagen se envía como data URL, sin necesitar un enlace público que el proveedor tenga que descargar.

```python
import argparse
import base64
import json
import mimetypes
import os
from pathlib import Path
import urllib.error
import urllib.request

URL = "https://api.mandapi.com/v1/chat/completions"

def main():
    parser = argparse.ArgumentParser()
    mode = parser.add_mutually_exclusive_group(required=True)
    mode.add_argument("--demo", action="store_true")
    mode.add_argument("--live", action="store_true")
    parser.add_argument("--model", default="MODEL_ID")
    parser.add_argument("--image", type=Path)
    parser.add_argument("--language", choices=("en", "es"), default="en")
    args = parser.parse_args()

    image_url = "data:image/jpeg;base64,IMAGE_BYTES"
    if args.live:
        key = os.environ.get("MANDAPI_API_KEY")
        if not key or args.model == "MODEL_ID" or not args.image:
            parser.error("--live needs a private key, a real --model and --image")
        mime = mimetypes.guess_type(args.image.name)[0]
        if mime not in {"image/jpeg", "image/png", "image/webp"}:
            parser.error("Use a JPEG, PNG or WebP image")
        image_url = "data:" + mime + ";base64," + base64.b64encode(
            args.image.read_bytes()
        ).decode("ascii")

    payload = {
        "model": args.model,
        "messages": [{
            "role": "user",
            "content": [
                {"type": "text", "text": (
                    "Enumera los objetos visibles con una descripción breve. "
                    "Indica la incertidumbre; no deduzcas medidas exactas."
                    if args.language == "es" else
                    "List the visible objects and a short description. "
                    "Say when uncertain. Do not infer exact measurements."
                )},
                {"type": "image_url", "image_url": {"url": image_url}}
            ]
        }],
        "max_tokens": 300
    }
    if args.demo:
        print(json.dumps({"mode": "offline-preview", "request": payload}, indent=2))
        return

    request = urllib.request.Request(
        URL, data=json.dumps(payload).encode("utf-8"),
        headers={"Authorization": "Bearer " + key,
                 "Content-Type": "application/json"}
    )
    try:
        with urllib.request.urlopen(request, timeout=90) as response:
            result = json.load(response)
    except urllib.error.HTTPError as error:
        raise SystemExit("MandAPI HTTP " + str(error.code)) from None
    print(result["choices"][0]["message"]["content"])

if __name__ == "__main__":
    main()
```

## Revisa la solicitud sin enviarla

```bash
python vision.py --demo --language es
```

El comando muestra la estructura con un marcador para los bytes de la imagen. No lee ninguna foto ni llama a MandAPI. Para tu prueba posterior, elige una imagen pequeña JPEG, PNG o WebP.

## Utiliza tu propia imagen

Configura la clave de forma privada en la misma terminal. En Bash:

```bash
read -rsp "Clave de MandAPI: " MANDAPI_API_KEY
printf '\n'
export MANDAPI_API_KEY
```

O en PowerShell:

```powershell
$env:MANDAPI_API_KEY = [Net.NetworkCredential]::new('', (Read-Host 'Clave de MandAPI' -AsSecureString)).Password
```

```bash
python vision.py --live --image foto.jpg --model MODEL_ID --language es
```

El comando explícito `--live` envía una solicitud con consumo. Después de ejecutarlo, compara la respuesta con la foto y revisa el consumo en MandAPI. Si lo integras en una web, mantén la clave en el backend.

## Resuelve errores habituales

Si el modelo rechaza imágenes, revisa su capacidad Vision actual y el identificador exacto. Una extensión correcta no arregla una imagen dañada: ábrela localmente y vuelve a exportarla si es necesario. Si se rechaza el archivo, revisa los formatos y tamaños admitidos por el modelo. Si rechaza `max_tokens`, utiliza el ajuste de salida documentado para ese modelo.

Empieza con una lista de objetos visibles o una descripción breve. Añade extracción estructurada después de comprobar el esquema; este ejemplo no garantiza cuadros de posición precisos.

## Referencias

- [https://app.mandapi.com/api/pricing](https://app.mandapi.com/api/pricing)
- [https://app.mandapi.com/catalog.json](https://app.mandapi.com/catalog.json)
- [https://openrouter.ai/docs/cookbook/image-understanding/find-objects-in-images](https://openrouter.ai/docs/cookbook/image-understanding/find-objects-in-images)
