Course EN
← back to chapter

Extraer campos

Pega un bloque desordenado — una firma de correo, un reenvío de presentación,

Showcase — Extraer campos

Pega un bloque desordenado — una firma de correo, un reenvío de presentación, un mensaje de chat — y recibe de vuelta un objeto JSON estricto: name, email, phone, company. El modelo llena lo que encuentra y regresa null en el resto en lugar de adivinar, porque el schema dice que esos campos son opcionales, no ausentes.

Córrelo

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

Abre http://localhost:3000.

Para correrlo contra Gemini:

PROVIDER=gemini docker compose up --build

Qué hay aquí

  • backend/ai_openai.py — el schema Contact + la llamada responses.parse
  • backend/ai_gemini.py — mismo schema, response_schema en el config
  • backend/main.py — loader de FastAPI idéntico; lee PROVIDER y despacha
  • frontend/app/page.tsx — textarea + resultado (renderizado como JSON)
  • docker-compose.yml — dos servicios, secrets montados desde ./secrets/

run(input: str) -> str regresa el objeto validado serializado a JSON legible, manteniendo el contrato idéntico entre los showcases de la semana.

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 extract-fields.zip

unzip extract-fields.zip
cd extract-fields
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

"""Week 4 - Showcase 1 (OpenAI): pull contact fields out of free text.

A schema in, a clean object out. The model fills what it finds and leaves
the rest null instead of guessing. The run() contract still returns a
string, so we serialize the validated object to pretty JSON for display.
"""
import json
from typing import Optional

from openai import OpenAI
from pydantic import BaseModel

_client = OpenAI()


class Contact(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    company: Optional[str] = None


def run(text: str) -> str:
    response = _client.responses.parse(
        model="gpt-5.4-nano",
        input="Extract the contact details from this text. Use null for "
              f"anything not present.\n\n{text.strip()}",
        text_format=Contact,
    )
    return json.dumps(response.output_parsed.model_dump(), indent=2)

backend/ai_gemini.py

"""Week 4 - Showcase 1 (Gemini): pull contact fields out of free text."""
import json
import os
from typing import Optional

from google import genai
from google.genai import types
from pydantic import BaseModel

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


class Contact(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    company: Optional[str] = None


def run(text: str) -> str:
    response = _client.models.generate_content(
        model="gemini-3.1-flash-lite",
        contents="Extract the contact details from this text. Use null for "
                 f"anything not present.\n\n{text.strip()}",
        config=types.GenerateContentConfig(
            response_mime_type="application/json",
            response_schema=Contact,
        ),
    )
    return json.dumps(response.parsed.model_dump(), indent=2)

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