Creació del primer informe
L’anàlisi pot trigar uns segons. L’API accepta el text, el processa fora de la petició inicial i ofereix un recurs independent per consultar-ne l’estat.
Autenticació
Les integracions directes requereixen una clau activa. Envia-la a la capçalera Authorization i no la incloguis en codi públic ni en aplicacions client.
Authorization: Bearer art_live_…
SDKs oficials
Via d’integració recomanada. Els clients oficials encapsulen el cicle asíncron complet —creació, espera conforme a Retry-After, reintents idempotents i recollida del resultat— en una única crida, sense dependències de tercers.
pip install artext# Instal·la el client oficial: pip install artext
# Executa aquest codi al servidor; no exposis mai la clau al navegador.
import os
from artext import Artext
client = Artext(
api_key=os.environ["ARTEXT_API_KEY"],
base_url="http://uned.tail9cc3dd.ts.net",
)
# analyze crea l'informe, espera respectant Retry-After i retorna el resultat.
# Una anàlisi fallida llança una excepció amb el detall de l'error.
report = client.analyze(
"En el dia d’avui es durà a terme la revisió de la sol·licitud.",
language="ca",
domain_slug="llenguatge-clar",
text_type_slug="text-juridic-administratiu-dirigit-a-la-ciutadania",
)
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// Instal·la el client oficial: npm install artext
// Executa aquest codi al servidor; no exposis mai la clau al navegador.
import { Artext } from "artext";
const client = new Artext({
apiKey: process.env.ARTEXT_API_KEY,
baseUrl: "http://uned.tail9cc3dd.ts.net",
});
// analyze crea l'informe, espera respectant Retry-After i retorna el resultat.
// Una anàlisi fallida llança una excepció amb el detall de l'error.
const report = await client.analyze({
text: "En el dia d’avui es durà a terme la revisió de la sol·licitud.",
language: "ca",
domainSlug: "llenguatge-clar",
textTypeSlug: "text-juridic-administratiu-dirigit-a-la-ciutadania",
});
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);
}
}
Els exemples següents mostren el cicle complet sobre HTTP, sense SDK. L’esquema openapi.json permet generar clients per a altres llenguatges.
Semàntica asíncrona
arText segueix la semàntica estàndard d’HTTP per a tasques que no acaben dins la petició inicial. No cal mantenir obert el POST ni triar un interval arbitrari.
202 AcceptedEl text ha estat acceptat, però l’anàlisi encara pot estar a la cua o executant-se. No significa que l’informe estigui complet.status_url + LocationIdentifiquen el recurs de l’informe. Consulta sempre aquesta mateixa URL; no repeteixis el POST per saber si ha acabat.Retry-AfterNombre mínim de segons que cal esperar abans de la consulta següent. Una consulta anterior pot rebre 429.events_urlFlux opcional Server-Sent Events amb els canvis d’estat. Si no l’utilitzes o s’interromp, status_url és el mecanisme de reserva.HTTP Semantics · 202HTTP Semantics · Retry-AfterHTML · Server-sent events
Seqüència d’integració
L’anàlisi no s’executa dins de la petició inicial: s’encua i es processa en segon pla. La integració consta dels cinc passos següents.
POST /v1/reportsS’envia el text pla, l’idioma i l’API key.
202 · report_id + status_urlL'API valida, encua i respon en mil·lisegons. Encara no hi ha resultat.
queued → runningEl motor analitza el text en segon pla, sense intervenció del client.
GET status_url · Retry-AfterEl client consulta l’estat conforme a Retry-After o se subscriu a events_url (SSE).
completed · resultL’informe complet es recull a result; una anàlisi fallida retorna failed amb l’error.
La petició de creació no s’ha de mantenir oberta a l’espera del resultat. La creació i la recollida de l’informe són operacions independents; aquesta separació permet tolerar anàlisis llargues, reinicis i proxies intermedis.
# Desa la clau fora del codi i carrega-la des de l’entorn.
# Requereix curl i jq.
# export ARTEXT_API_KEY='art_live_...'
set -euo pipefail
API_BASE='http://uned.tail9cc3dd.ts.net'
IDEMPOTENCY_KEY="report-$(date +%s)-$RANDOM"
headers_file=$(mktemp)
trap 'rm -f "$headers_file"' EXIT
# Crea l’informe una sola vegada. Idempotency-Key permet repetir el POST amb seguretat després d’un error de xarxa.
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":"ca","domain_slug":"llenguatge-clar","text_type_slug":"text-juridic-administratiu-dirigit-a-la-ciutadania","text":"En el dia d’avui es durà a terme la revisió de la sol·licitud.","external_id":"document-123"}')
# status_url és relatiu: resol-lo 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 mateix informe respectant Retry-After i amb un límit 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
# Processa el resultat només despré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
# Desa la clau fora del codi i carrega-la des de l’entorn.
API_BASE = 'http://uned.tail9cc3dd.ts.net'
API_KEY = os.environ["ARTEXT_API_KEY"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
payload = {'language': 'ca', 'domain_slug': 'llenguatge-clar', 'text_type_slug': 'text-juridic-administratiu-dirigit-a-la-ciutadania', 'text': 'En el dia d’avui es durà a terme la revisió de la sol·licitud.', 'external_id': 'document-123'}
# Crea l’informe una sola vegada. Idempotency-Key permet repetir el POST amb seguretat després d’un error de xarxa.
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 és relatiu: resol-lo contra API_BASE.
status_url = urljoin(f"{API_BASE}/", created["status_url"])
retry_after = int(response.headers.get("Retry-After", "2"))
# Consulta el mateix informe respectant Retry-After i amb un límit 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")
# Processa el resultat només despré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+. Executa aquest codi al servidor; no exposis mai la clau al navegador.
const API_BASE = "http://uned.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 l’informe una sola vegada. Idempotency-Key permet repetir el POST amb seguretat després d’un error de xarxa.
const createdResponse = await api("v1/reports", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({"language":"ca","domain_slug":"llenguatge-clar","text_type_slug":"text-juridic-administratiu-dirigit-a-la-ciutadania","text":"En el dia d’avui es durà a terme la revisió de la sol·licitud.","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 mateix informe respectant Retry-After i amb un límit 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");
}
// Processa el resultat només despré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);
}Defineix ARTEXT_API_KEY a l’entorn. Els exemples respecten Retry-After, recomanen Idempotency-Key i abandonen al cap de 3 minuts.
Cicle de vida de l’informe
POST respon 202; l’anàlisi continua a la cua. Utilitza el flux SSE d’events_url o consulta status_url fins a arribar a un estat terminal, sense tornar a crear l’informe.
queuedAcceptat i pendent. Espera abans de tornar a consultar.
runningL’analitzador està treballant. Continua el polling.
completedEstat terminal correcte. result conté l’informe.
failedEstat terminal fallit. Registra error i X-Request-ID.
SSE és opcional. Si fas polling, respecta sempre Retry-After; una consulta prematura rep 429. No interpretis position_in_queue com una estimació temporal.
202 · A la cua
{
"events_url": "/v1/reports/rep_7f12a4c8/events",
"external_id": "document-123",
"report_id": "rep_7f12a4c8",
"status": "queued",
"status_url": "/v1/reports/rep_7f12a4c8"
}