Creación del primer informe
El análisis puede tardar varios segundos. La API acepta el texto, lo procesa fuera de la petición inicial y ofrece un recurso independiente para consultar su estado.
Autenticación
Las integraciones directas requieren una clave activa. Envíala en la cabecera Authorization y no la incluyas en código público ni en aplicaciones cliente.
Authorization: Bearer art_live_…
SDKs oficiales
Vía de integración recomendada. Los clientes oficiales encapsulan el ciclo asíncrono completo —creación, espera conforme a Retry-After, reintentos idempotentes y recogida del resultado— en una única llamada, sin dependencias de terceros.
pip install artext-client# Instala el cliente oficial: pip install artext-client
# Ejecuta este código en servidor; nunca expongas la clave en el navegador.
import os
from artext_client import ArtextClient
client = ArtextClient(
api_key=os.environ["ARTEXT_API_KEY"],
base_url="http://wuned.tail9cc3dd.ts.net",
)
# analyze crea el informe, espera respetando Retry-After y devuelve el resultado.
# Un análisis fallido lanza una excepción con el detalle del error.
report = client.analyze("En el día de hoy se realizará la revisión de la solicitud.", language="es")
print(report.result.measurement("word-count").value)
for suggestion in report.result.suggestions:
print(suggestion.metric_id, suggestion.summary)
for occurrence in suggestion.occurrences:
print(" ", occurrence.text, "->", occurrence.replacement)
npm install artext-client// Instala el cliente oficial: npm install artext-client
// Ejecuta este código en servidor; nunca expongas la clave en el navegador.
import { ArtextClient } from "artext-client";
const client = new ArtextClient({
apiKey: process.env.ARTEXT_API_KEY,
baseUrl: "http://wuned.tail9cc3dd.ts.net",
});
// analyze crea el informe, espera respetando Retry-After y devuelve el resultado.
// Un análisis fallido lanza una excepción con el detalle del error.
const report = await client.analyze({ text: "En el día de hoy se realizará la revisión de la solicitud.", language: "es" });
for (const suggestion of report.result.suggestions) {
console.log(suggestion.metric_id, suggestion.summary);
for (const occurrence of suggestion.occurrences) {
console.log(" ", occurrence.text, "->", occurrence.replacement);
}
}
Los ejemplos siguientes muestran el ciclo completo sobre HTTP, sin SDK. El esquema openapi.json permite generar clientes para otros lenguajes.
Semántica asíncrona
arText sigue la semántica estándar de HTTP para trabajos que no terminan dentro de la petición inicial. No es necesario mantener abierto el POST ni elegir un intervalo de consulta arbitrario.
202 AcceptedEl texto ha sido aceptado, pero el análisis todavía puede estar en cola o ejecutándose. No significa que el informe esté completado.status_url + LocationIdentifican el recurso del informe. Consulta siempre esa misma URL; no repitas el POST para saber si ha terminado.Retry-AfterNúmero mínimo de segundos que debes esperar antes de la siguiente consulta. Una consulta anterior puede recibir 429.events_urlFlujo opcional Server-Sent Events con los cambios de estado. Si no lo utilizas o se interrumpe, status_url es el respaldo.HTTP Semantics · 202HTTP Semantics · Retry-AfterHTML · Server-sent events
Secuencia de integración
El análisis no se ejecuta dentro de la petición inicial: se encola y se procesa en segundo plano. La integración consta de los cinco pasos siguientes.
POST /v1/reportsSe envía el texto plano, el idioma y la API key.
202 · report_id + status_urlLa API valida, encola y responde en milisegundos. Todavía no hay resultado.
queued → runningEl motor analiza el texto en segundo plano, sin intervención del cliente.
GET status_url · Retry-AfterEl cliente consulta el estado conforme a Retry-After o se suscribe a events_url (SSE).
completed · resultEl informe completo se recoge en result; un análisis fallido devuelve failed con el error.
La petición de creación no debe mantenerse abierta a la espera del resultado. La creación y la recogida del informe son operaciones independientes; esta separación permite tolerar análisis largos, reinicios y proxies intermedios.
# Guarda la clave fuera del código y cárgala desde el entorno.
# Requiere curl y jq.
# export ARTEXT_API_KEY='art_live_...'
set -euo pipefail
API_BASE='http://wuned.tail9cc3dd.ts.net'
IDEMPOTENCY_KEY="report-$(date +%s)-$RANDOM"
headers_file=$(mktemp)
trap 'rm -f "$headers_file"' EXIT
# Crea el informe una sola vez. Idempotency-Key hace seguro repetir el POST tras un fallo de red.
created=$(curl --fail-with-body --silent --show-error --dump-header "$headers_file" \
--request POST "$API_BASE/v1/reports" \
--header "Authorization: Bearer $ARTEXT_API_KEY" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header 'Content-Type: application/json' \
--data-binary '{"language":"es","genre":"informe","text":"En el día de hoy se realizará la revisión de la solicitud.","external_id":"document-123"}')
# status_url es relativo: resuélvelo contra API_BASE.
status_url="$API_BASE$(jq -r '.status_url' <<<"$created")"
retry_after=$(awk 'BEGIN { IGNORECASE=1 } /^Retry-After:/ { gsub("\r", "", $2); print $2 }' "$headers_file" | tail -1)
retry_after=${retry_after:-2}
# Consulta el mismo informe respetando Retry-After y con un límite total.
for attempt in $(seq 1 90); do
sleep "$retry_after"
report=$(curl --fail-with-body --silent --show-error --dump-header "$headers_file" \
--header "Authorization: Bearer $ARTEXT_API_KEY" \
"$status_url")
status=$(jq -r '.status' <<<"$report")
case "$status" in
completed) break ;;
failed) jq -r '.error.message // "Analysis failed"' <<<"$report" >&2; exit 1 ;;
queued|running)
retry_after=$(awk 'BEGIN { IGNORECASE=1 } /^Retry-After:/ { gsub("\r", "", $2); print $2 }' "$headers_file" | tail -1)
retry_after=${retry_after:-2}
;;
*) echo "Unknown status: $status" >&2; exit 1 ;;
esac
done
# Procesa el resultado únicamente después de completed.
test "$status" = completed || { echo 'Polling timed out' >&2; exit 1; }
jq '.result.measurements, .result.suggestions' <<<"$report"import os
import time
import uuid
from urllib.parse import urljoin
import requests
# Guarda la clave fuera del código y cárgala desde el entorno.
API_BASE = 'http://wuned.tail9cc3dd.ts.net'
API_KEY = os.environ["ARTEXT_API_KEY"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
payload = {'language': 'es', 'genre': 'informe', 'text': 'En el día de hoy se realizará la revisión de la solicitud.', 'external_id': 'document-123'}
# Crea el informe una sola vez. Idempotency-Key hace seguro repetir el POST tras un fallo de red.
response = requests.post(
f"{API_BASE}/v1/reports",
headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
json=payload,
timeout=30,
)
response.raise_for_status()
created = response.json()
# status_url es relativo: resuélvelo contra API_BASE.
status_url = urljoin(f"{API_BASE}/", created["status_url"])
retry_after = int(response.headers.get("Retry-After", "2"))
# Consulta el mismo informe respetando Retry-After y con un límite total.
deadline = time.monotonic() + 180
while True:
time.sleep(retry_after)
response = requests.get(status_url, headers=HEADERS, timeout=30)
retry_after = int(response.headers.get("Retry-After", "2"))
if response.status_code == 429:
continue
response.raise_for_status()
report = response.json()
status = report["status"]
if status == "completed":
break
if status == "failed":
raise RuntimeError((report.get("error") or {}).get("message") or "Analysis failed")
if status not in {"queued", "running"}:
raise RuntimeError(f"Unknown report status: {status}")
if time.monotonic() >= deadline:
raise TimeoutError("Report polling timed out")
# Procesa el resultado únicamente después de completed.
result = report["result"]
for measurement in result["measurements"]:
print(measurement["metric_id"], measurement["value"], measurement["unit"])
for index, suggestion in enumerate(result["suggestions"]):
print(index, suggestion["metric_id"], len(suggestion["occurrences"]))// Node.js 18+. Ejecuta este código en servidor; nunca expongas la clave en el navegador.
const API_BASE = "http://wuned.tail9cc3dd.ts.net";
const API_KEY = process.env.ARTEXT_API_KEY;
if (!API_KEY) throw new Error("ARTEXT_API_KEY is required");
const headers = {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json"
};
const api = async (path, options = {}) => {
const response = await fetch(new URL(path, `${API_BASE}/`), {
...options,
headers: { ...headers, ...options.headers },
signal: AbortSignal.timeout(30_000)
});
if (!response.ok && response.status !== 429) {
throw new Error(`${response.status}: ${await response.text()}`);
}
return response;
};
const delay = (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
// Crea el informe una sola vez. Idempotency-Key hace seguro repetir el POST tras un fallo de red.
const createdResponse = await api("v1/reports", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({"language":"es","genre":"informe","text":"En el día de hoy se realizará la revisión de la solicitud.","external_id":"document-123"})
});
const created = await createdResponse.json();
const deadline = Date.now() + 180_000;
let retryAfter = Number(createdResponse.headers.get("Retry-After") || 2);
let report;
// Consulta el mismo informe respetando Retry-After y con un límite total.
while (Date.now() < deadline) {
await delay(retryAfter * 1_000);
const statusResponse = await api(created.status_url);
retryAfter = Number(statusResponse.headers.get("Retry-After") || 2);
if (statusResponse.status === 429) continue;
report = await statusResponse.json();
if (report.status === "completed") break;
if (report.status === "failed") {
throw new Error(report.error?.message || "Analysis failed");
}
if (!["queued", "running"].includes(report.status)) {
throw new Error(`Unknown report status: ${report.status}`);
}
}
if (report?.status !== "completed") {
throw new Error("Report polling timed out");
}
// Procesa el resultado únicamente después de completed.
for (const item of report.result.measurements) {
console.log(item.metric_id, item.value, item.unit);
}
for (const [index, item] of report.result.suggestions.entries()) {
console.log(index, item.metric_id, item.occurrences.length);
}Define ARTEXT_API_KEY en el entorno. Los ejemplos respetan Retry-After, recomiendan Idempotency-Key y abandonan tras 3 minutos.
Ciclo de vida del informe
POST responde 202; el análisis continúa en la cola. Usa el flujo SSE de events_url o consulta status_url hasta alcanzar un estado terminal, sin crear de nuevo el informe.
queuedAceptado y pendiente. Espera antes de volver a consultar.
runningEl analizador está trabajando. Continúa el polling.
completedEstado terminal correcto. result contiene el informe.
failedEstado terminal fallido. Registra error y X-Request-ID.
SSE es opcional. El polling debe respetar siempre Retry-After; una consulta prematura recibe 429. position_in_queue no debe interpretarse como una estimación temporal.
202 · En cola
{
"events_url": "/v1/reports/rep_7f12a4c8/events",
"external_id": "document-123",
"report_id": "rep_7f12a4c8",
"status": "queued",
"status_url": "/v1/reports/rep_7f12a4c8"
}