Elige registros que controles
Esta receta exporta el archivo usage-events.jsonl creado por tu aplicación en la guía de seguimiento. Genera un CSV para revisión operativa. No es una factura, una exportación completa de la cuenta MandAPI ni una reconstrucción de cargos reales.
Utiliza las vistas de registros y estadísticas de tu cuenta para consultar la actividad de la plataforma. Este script trabaja solo con registros de tu aplicación; no utiliza un botón de exportación de la plataforma ni un endpoint público de exportación. Consulta los créditos reales en el panel de MandAPI.
Guarda y prueba el exportador
Guárdalo como export_activity.py. Solo necesita la biblioteca estándar de Python. Empieza con --demo: no lee datos de una cuenta ni realiza solicitudes de red.
import argparse
import csv
from datetime import datetime
import json
from pathlib import Path
FIELDS = ("record_type", "time", "request_id", "feature", "model", "status",
"prompt_tokens", "completion_tokens", "duration_ms")
NUMBERS = {"prompt_tokens", "completion_tokens", "duration_ms"}
def safe_text(value):
if not isinstance(value, str) or len(value) > 200:
raise ValueError("Expected a short text field")
text = value.replace("\r", " ").replace("\n", " ")
return "'" + text if text.lstrip().startswith(("=", "+", "-", "@")) else text
def clean(event):
if not isinstance(event, dict) or event.get("status") not in {"ok", "error"}:
raise ValueError("Invalid event status")
timestamp = datetime.fromisoformat(event["time"])
if timestamp.tzinfo is None:
raise ValueError("Timestamp must include a time zone")
row = {}
for field in FIELDS:
if field == "record_type":
row[field] = "application_usage_not_billing"
elif field in NUMBERS:
value = event.get(field)
if value is not None and (type(value) is not int or value < 0):
raise ValueError("Token and duration fields must be nonnegative integers")
row[field] = "" if value is None else value
else:
row[field] = safe_text(event.get(field, ""))
return row
parser = argparse.ArgumentParser()
parser.add_argument("source", nargs="?")
parser.add_argument("--output", default="usage-activity.csv")
parser.add_argument("--demo", action="store_true")
args = parser.parse_args()
if args.demo:
events = [
{"time": "2026-10-30T09:00:00+00:00", "request_id": "demo-1", "feature": "support", "model": "MODEL_ID", "status": "ok", "prompt_tokens": 12, "completion_tokens": 5, "duration_ms": 400},
{"time": "2026-10-30T09:01:00+00:00", "request_id": "demo-2", "feature": "=2+2", "status": "error", "duration_ms": 200, "api_key": "DROP_THIS_FIELD"},
]
else:
if not args.source:
parser.error("Provide your own usage-events.jsonl or choose --demo")
with Path(args.source).open(encoding="utf-8") as handle:
events = [json.loads(line) for line in handle if line.strip()]
rows = [clean(event) for event in events]
with Path(args.output).open("x", newline="", encoding="utf-8-sig") as handle:
writer = csv.DictWriter(handle, fieldnames=FIELDS)
writer.writeheader()
writer.writerows(rows)
print(json.dumps({"rows": len(rows), "output": args.output, "billing_report": False}))python export_activity.py --demo --output usage-demo.csvLa demostración crea dos filas. La solicitud fallida deja vacíos los tokens porque su uso es desconocido; vacío no equivale a cero. El campo adicional api_key queda fuera de las columnas permitidas y el valor de función con aspecto de fórmula se escribe como texto.
El archivo de salida no debe existir. Comprueba el resultado en el programa de hojas de cálculo que utilices: añadir un prefijo a posibles fórmulas es una protección básica, no sustituye el tratamiento cuidadoso de archivos no confiables.
Exporta tu propio registro
Utiliza una copia local con registros que tengas derecho a procesar. El ejemplo de seguimiento usa fechas con zona horaria, un ID propio por solicitud, estado y tokens cuando fueron devueltos.
python export_activity.py usage-events.jsonl --output usage-activity.csvSolo se exportan las columnas indicadas. Se omiten prompts, respuestas, claves, identificadores de usuarios y campos adicionales. El script rechaza estados no válidos, fechas sin zona y tokens negativos o no enteros. No modifica el registro original.
Para servicios grandes, exporta una consulta autorizada y limitada de tu base de datos en lugar de cargar un archivo sin límite. Define quién puede descargar el informe y durante cuánto tiempo se conserva.
Concilia y comprueba el resultado
Compara las filas con el intervalo seleccionado. Los eventos ausentes, reintentos, uso de streaming incompleto y solicitudes de otras aplicaciones pueden dejar fuera actividad. Los tokens de una respuesta no establecen por sí solos el crédito cobrado.
El CSV de demostración debe tener dos filas de datos, la marca application_usage_not_billing y tokens vacíos para el fallo. Comprueba que no aparece el campo inesperado api_key. Investiga diferencias de facturación con registros reales del panel; no calcules importes suponiendo que el uso desconocido es cero.