Course EN
← back to chapter

Descripción de imagen

Pega una image URL pública y obtén un caption estilo alt-text para accesibilidad

Showcase — Descripción de imagen

Pega una image URL pública y obtén un caption estilo alt-text para accesibilidad más una descripción corta. Es la llamada multimodal más simple: un solo mensaje cuyo contenido es una parte de texto con la instrucción y una parte de imagen, razonadas juntas.

Córrelo

bash bootstrap-secrets.sh              # reads ../../../../.env, writes secrets/
docker compose up --build              # default: PROVIDER=openai

Abre http://localhost:3000. Gemini: PROVIDER=gemini docker compose up --build.

Qué hay aquí

  • backend/ai_openai.py — pasa la image URL directo al modelo.
  • backend/ai_gemini.py — descarga la imagen y la pasa como bytes inline.
  • frontend/app/page.tsx — caja de URL + caption.

Detenlo

docker compose down

Ejecútalo en tu máquina

Descarga el proyecto como ZIP y córrelo con Docker. Levanta un backend FastAPI y un frontend Next.js en localhost:3000.

Descargar image-caption.zip

unzip image-caption.zip
cd image-caption
bash bootstrap-secrets.sh   # one-time: pulls API keys into ./secrets
docker compose up --build   # default provider: openai
# or:  PROVIDER=gemini docker compose up --build

Escribe algo, elige un proveedor y ejecuta el mismo código de Código contra la API real. Requiere iniciar sesión.


  

Los mismos módulos que ejecuta el botón Run. El proyecto completo (frontend, Dockerfile, compose) está en el ZIP, pestaña README.

backend/ai_openai.py

"""Showcase 1 (OpenAI): image captioning from a URL.

Paste a public image URL and get an accessibility-style caption plus a short
description. One multimodal message: an instruction text part and an image part.
"""
from openai import OpenAI

_client = OpenAI()

_MODEL = "gpt-5.4-nano"

_PROMPT = (
    "Write a concise one-sentence alt-text caption for this image, then a "
    "2-3 sentence description of what's in it. Label them 'Alt text:' and "
    "'Description:'."
)


def run(image_url: str) -> str:
    url = image_url.strip()
    if not url.startswith("http"):
        return "Paste a public image URL (starting with http:// or https://)."
    response = _client.responses.create(
        model=_MODEL,
        input=[{
            "role": "user",
            "content": [
                {"type": "input_text", "text": _PROMPT},
                {"type": "input_image", "image_url": url},
            ],
        }],
    )
    return response.output_text

backend/ai_gemini.py

"""Showcase 1 (Gemini): image captioning from a URL.

Same captioning prompt; Gemini takes the image as downloaded bytes.
"""
import os
import urllib.request

from google import genai
from google.genai import types

_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

_MODEL = "gemini-3.1-flash-lite"

_PROMPT = (
    "Write a concise one-sentence alt-text caption for this image, then a "
    "2-3 sentence description of what's in it. Label them 'Alt text:' and "
    "'Description:'."
)


def _mime(url: str) -> str:
    u = url.lower()
    if u.endswith(".png"):
        return "image/png"
    if u.endswith(".webp"):
        return "image/webp"
    return "image/jpeg"


def run(image_url: str) -> str:
    url = image_url.strip()
    if not url.startswith("http"):
        return "Paste a public image URL (starting with http:// or https://)."
    image_bytes = urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})).read()
    response = _client.models.generate_content(
        model=_MODEL,
        contents=[types.Part.from_bytes(data=image_bytes, mime_type=_mime(url)), _PROMPT],
    )
    return response.text or ""

Archivos del proyecto

  • .gitignore
  • README.es.md
  • README.md
  • backend/Dockerfile
  • backend/ai_gemini.py
  • backend/ai_openai.py
  • backend/main.py
  • backend/requirements.txt
  • bootstrap-secrets.sh
  • docker-compose.yml
  • frontend/Dockerfile
  • frontend/app/layout.tsx
  • frontend/app/page.tsx
  • frontend/next.config.ts
  • frontend/package.json
  • frontend/tsconfig.json