Preguntas y respuestas sobre documentos
Chatea con tu propio documento: long context (sem. 13) + grounding (sem. 9) + una revisión de moderación (sem. 16). Pega un documento, pon tu pregunta en una línea `Q:`, y recibe una respuesta anclada en el texto.
Showcase — Preguntas y respuestas sobre documentos
Chatea con tu propio documento: long context (sem. 13) + grounding (sem. 9) + una revisión de moderación (sem. 16). Pega un documento, pon tu pregunta en una línea Q:, y recibe una respuesta anclada en el texto.
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/backend/ai_gemini.py— parsea doc + pregunta, modera, respuesta con grounding.frontend/app/page.tsx— caja de documento + pregunta, respuesta con grounding.
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 qa-over-docs.zip
cd qa-over-docs
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 3 (OpenAI): grounded Q&A over your own document.
Paste a document and a question (on a 'Q:' line) and get an answer grounded in
the text, with the question moderated first. Long context (week 13) plus
grounding (week 9) plus a safety check (week 16) — the everyday "chat with a
document" feature, built from parts you now know cold.
"""
from openai import OpenAI
_client = OpenAI()
_MODEL = "gpt-5.4-nano"
def run(text: str) -> str:
body = text.strip()
if "Q:" in body:
idx = body.rfind("Q:")
document, question = body[:idx].strip(), body[idx + 2:].strip()
else:
document, question = body, "Summarize this document."
if not document:
return "Paste a document, then put your question on a line starting with 'Q:'."
if _client.moderations.create(model="omni-moderation-latest", input=question).results[0].flagged:
return "[question blocked by moderation]"
response = _client.responses.create(
model=_MODEL,
instructions=f"Answer the question using ONLY this document. Quote the relevant part. If it "
f"isn't covered, say so.\n\nDOCUMENT:\n{document}",
input=[{"role": "user", "content": question}],
)
return response.output_text
backend/ai_gemini.py
"""Showcase 3 (Gemini): grounded Q&A over your own document.
Same long-context + grounding + moderation flow, on Gemini.
"""
import os
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"
def _flagged(text: str) -> bool:
r = _client.models.generate_content(
model=_MODEL, contents=[types.Content(role="user", parts=[types.Part(text=text)])],
config=types.GenerateContentConfig(system_instruction=(
"Reply 'flag' if this text is hateful, harassing, sexual, violent, or dangerous; else 'ok'. One word.")),
)
return "flag" in (r.text or "").lower()
def run(text: str) -> str:
body = text.strip()
if "Q:" in body:
idx = body.rfind("Q:")
document, question = body[:idx].strip(), body[idx + 2:].strip()
else:
document, question = body, "Summarize this document."
if not document:
return "Paste a document, then put your question on a line starting with 'Q:'."
if _flagged(question):
return "[question blocked by moderation]"
response = _client.models.generate_content(
model=_MODEL,
contents=[types.Content(role="user", parts=[types.Part(text=question)])],
config=types.GenerateContentConfig(
system_instruction=f"Answer the question using ONLY this document. Quote the relevant part. "
f"If it isn't covered, say so.\n\nDOCUMENT:\n{document}",
),
)
return response.text or ""
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