Reescribe el tono
Pega cualquier mensaje (correo, Slack, mensaje de commit), elige un tono, y
Showcase — Reescribe el tono
Pega cualquier mensaje (correo, Slack, mensaje de commit), elige un tono, y recíbelo reescrito con los mismos datos y otra voz. Sigue siendo una sola llamada a la API.
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 en su lugar:
PROVIDER=gemini docker compose up --build
Qué hay aquí
backend/ai_openai.py— la llamada a OpenAIbackend/ai_gemini.py— la llamada a Geminibackend/main.py— loader de FastAPI idéntico; lee PROVIDER y despachafrontend/app/page.tsx— textarea +<select>de tono + resultadodocker-compose.yml— dos servicios, secrets montados desde./secrets/
El frontend codifica <tone>\n---\n<message> en el input de un solo string
que el backend espera, que es como el contrato def run(input: str) -> str
se mantiene igual en los tres showcases de esta 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.
unzip rewrite-tone.zip
cd rewrite-tone
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 1 - Showcase 2 (OpenAI): rewrite a message in a chosen tone.
The frontend encodes the input as "<tone>\\n---\\n<message>" so the
def run(input: str) -> str contract stays the same as the other showcases.
"""
from openai import OpenAI
_client = OpenAI()
def run(payload: str) -> str:
tone, _, message = payload.partition("\n---\n")
tone = (tone or "neutral").strip().lower()
message = (message or payload).strip()
prompt = (
f"Rewrite the following message in a {tone} tone. Preserve every fact, "
"name, date, and number. Do not add or remove information. Return only "
"the rewritten message, no preamble."
f"\n\n---\n{message}\n---"
)
# Cap the response so the model can't run away on us. 2048 tokens
# is roughly 6k characters — comfortably more than any reasonable
# rewrite of an 8k-char input.
response = _client.responses.create(
model="gpt-5.4-nano", input=prompt, max_output_tokens=2048,
)
return response.output_text
backend/ai_gemini.py
"""Week 1 - Showcase 2 (Gemini): rewrite a message in a chosen tone."""
import os
from google import genai
from google.genai import types
_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
def run(payload: str) -> str:
tone, _, message = payload.partition("\n---\n")
tone = (tone or "neutral").strip().lower()
message = (message or payload).strip()
prompt = (
f"Rewrite the following message in a {tone} tone. Preserve every fact, "
"name, date, and number. Do not add or remove information. Return only "
"the rewritten message, no preamble."
f"\n\n---\n{message}\n---"
)
# Cap the response so the model can't run away on us. 2048 tokens
# is roughly 6k characters — comfortably more than any reasonable
# rewrite of an 8k-char input.
response = _client.models.generate_content(
model="gemini-3.1-flash-lite", contents=prompt,
config=types.GenerateContentConfig(max_output_tokens=2048),
)
return response.text
Archivos del proyecto
.gitignoreREADME.es.mdREADME.mdbackend/Dockerfilebackend/ai_gemini.pybackend/ai_openai.pybackend/main.pybackend/requirements.txtbootstrap-secrets.shdocker-compose.ymlfrontend/Dockerfilefrontend/app/layout.tsxfrontend/app/page.tsxfrontend/next.config.tsfrontend/package.jsonfrontend/tsconfig.json