Course EN
← back to chapter

Constructor de dataset

Convierte ejemplos en un archivo de entrenamiento limpio — una línea como `user prompt => desired answer`, y sale JSONL válido (formato chat de OpenAI, o pares input/output de Gemini). Sin llamada al modelo; esto es puro plumbing de datos, el verdadero grueso del trabajo de fine-tuning.

Showcase — Constructor de dataset

Convierte ejemplos en un archivo de entrenamiento limpio — una línea como user prompt => desired answer, y sale JSONL válido (formato chat de OpenAI, o pares input/output de Gemini). Sin llamada al modelo; esto es puro plumbing de datos, el verdadero grueso del trabajo de fine-tuning.

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 — emite JSONL de chat de OpenAI.
  • backend/ai_gemini.py — emite JSONL de tuning de Gemini (input/output).
  • frontend/app/page.tsx — ejemplos a la entrada, dataset formateado a la salida.

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 dataset-builder.zip

unzip dataset-builder.zip
cd dataset-builder
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): build a fine-tune dataset.

The unglamorous 80% of fine-tuning: turning examples into a clean training file.
Paste one example per line as `user prompt => desired answer` and get valid
OpenAI chat JSONL back, with a count and a nudge if you're short on examples. No
model call — this is pure data plumbing, which is exactly the point.
"""
import json

_SEPARATORS = ("=>", "|", "\t")


def _split(line: str):
    for sep in _SEPARATORS:
        if sep in line:
            u, a = line.split(sep, 1)
            return u.strip(), a.strip()
    return None


def run(text: str) -> str:
    pairs = [p for p in (_split(l.strip()) for l in text.strip().splitlines() if l.strip()) if p]
    if not pairs:
        return "Enter one example per line as:  user prompt => desired answer"
    lines = [
        json.dumps({"messages": [
            {"role": "user", "content": u},
            {"role": "assistant", "content": a},
        ]})
        for u, a in pairs
    ]
    jsonl = "\n".join(lines)
    note = f"\n\n--- {len(pairs)} example(s), valid OpenAI chat JSONL ---"
    if len(pairs) < 10:
        note += "\n(real fine-tunes want 50+ examples; this validates the format)"
    return jsonl + note

backend/ai_gemini.py

"""Showcase 1 (Gemini): build a fine-tune dataset.

Same input, Gemini's tuning format — simple input/output pairs as JSONL rather
than full chat messages. Seeing both formats side by side is the lesson: the data
shape is provider-specific, the discipline (consistent examples) is not.
"""
import json

_SEPARATORS = ("=>", "|", "\t")


def _split(line: str):
    for sep in _SEPARATORS:
        if sep in line:
            u, a = line.split(sep, 1)
            return u.strip(), a.strip()
    return None


def run(text: str) -> str:
    pairs = [p for p in (_split(l.strip()) for l in text.strip().splitlines() if l.strip()) if p]
    if not pairs:
        return "Enter one example per line as:  user prompt => desired answer"
    lines = [json.dumps({"text_input": u, "output": a}) for u, a in pairs]
    jsonl = "\n".join(lines)
    note = f"\n\n--- {len(pairs)} example(s), Gemini tuning format ---"
    if len(pairs) < 10:
        note += "\n(real tunes want hundreds of examples; this validates the format)"
    return jsonl + note

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