Documentation Index
Fetch the complete documentation index at: https://docs.neuracall.com/llms.txt
Use this file to discover all available pages before exploring further.
Instalacion
pip install requests
Cliente Completo
import os
import json
import time
import requests
from typing import Optional, Dict, Any, List
class NeuracallClient:
"""Cliente para la API de Neuracall"""
def __init__(
self,
client_id: Optional[str] = None,
client_secret: Optional[str] = None,
base_url: str = "https://api.neuracall.com"
):
self.base_url = base_url
self.client_id = client_id or os.environ["NEURACALL_CLIENT_ID"]
self.client_secret = client_secret or os.environ["NEURACALL_CLIENT_SECRET"]
self._token = None
self._expires_at = 0
def _get_token(self) -> str:
"""Obtiene o renueva el token de acceso"""
if time.time() > self._expires_at - 300:
response = requests.post(
f"{self.base_url}/v1/auth",
json={
"client_id": self.client_id,
"client_secret": self.client_secret
}
)
response.raise_for_status()
data = response.json()
self._token = data["access_token"]
self._expires_at = data["expires_at"]
return self._token
def _headers(self) -> Dict[str, str]:
"""Headers con autorizacion"""
return {"Authorization": f"Bearer {self._get_token()}"}
# ==================== CALL ANALYSIS ====================
def create_analysis(
self,
audio_path: str,
external_id: str,
agent_id: str,
agent_name: str,
model_name: str,
additional_parameters: Optional[Dict] = None
) -> Dict[str, Any]:
"""
Crea un nuevo análisis de llamada.
Args:
audio_path: Ruta al archivo de audio
external_id: ID externo de la llamada
agent_id: ID del agente
agent_name: Nombre del agente
model_name: Nombre del modelo de análisis
additional_parameters: Metadatos adicionales opciónales
Returns:
Datos del análisis creado
"""
with open(audio_path, "rb") as audio_file:
files = {"audio_file": audio_file}
data = {
"external_id": external_id,
"agent_id": agent_id,
"agent_name": agent_name,
"model_name": model_name
}
if additional_parameters:
data["additional_parameters"] = json.dumps(additional_parameters)
response = requests.post(
f"{self.base_url}/v1/call-analysis",
headers=self._headers(),
files=files,
data=data
)
response.raise_for_status()
return response.json()
def get_analysis(self, analysis_id: str) -> Dict[str, Any]:
"""Obtiene un análisis por ID"""
response = requests.get(
f"{self.base_url}/v1/call-analysis/{analysis_id}",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def list_analyses(
self,
model_id: Optional[int] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
page: int = 0,
size: int = 20
) -> Dict[str, Any]:
"""Lista análisis con filtros y paginación"""
params = {"page": page, "size": size}
if model_id:
params["model_id"] = model_id
if start_date:
params["start_date"] = start_date
if end_date:
params["end_date"] = end_date
response = requests.get(
f"{self.base_url}/v1/call-analysis",
headers=self._headers(),
params=params
)
response.raise_for_status()
return response.json()
def get_transcription(self, analysis_id: str) -> Dict[str, Any]:
"""Obtiene la transcripción de un análisis"""
response = requests.get(
f"{self.base_url}/v1/call-analysis/{analysis_id}/transcription",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def wait_for_completion(
self,
analysis_id: str,
timeout: int = 600,
poll_interval: int = 5
) -> Dict[str, Any]:
"""
Espera a que un análisis se complete.
Args:
analysis_id: ID del análisis
timeout: Tiempo máximo de espera en segúndos
poll_interval: Intervalo entre consultas en segúndos
Returns:
Datos del análisis completado
"""
start = time.time()
while time.time() - start < timeout:
result = self.get_analysis(analysis_id)
status = result["status"]
if status == "PROCESS_COMPLETED":
return result
elif status == "ERROR":
raise Exception(f"Analysis failed: {result.get('error_message')}")
time.sleep(poll_interval)
raise TimeoutError(f"Analysis {analysis_id} did not complete within {timeout}s")
# ==================== MODELS ====================
def list_models(self, order_by_name: bool = False) -> List[Dict[str, Any]]:
"""Lista todos los modelos de análisis"""
response = requests.get(
f"{self.base_url}/v1/models",
headers=self._headers(),
params={"order_by_name": order_by_name}
)
response.raise_for_status()
return response.json()
def get_model(self, model_id: int) -> Dict[str, Any]:
"""Obtiene un modelo por ID"""
response = requests.get(
f"{self.base_url}/v1/models/{model_id}",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def create_model(
self,
name: str,
description: str,
prompt: str
) -> Dict[str, Any]:
"""Crea un nuevo modelo de análisis"""
response = requests.post(
f"{self.base_url}/v1/models",
headers=self._headers(),
json={
"name": name,
"description": description,
"prompt": prompt
}
)
response.raise_for_status()
return response.json()
# ==================== MODEL CATEGORIES ====================
def list_categories(self, model_id: int) -> List[Dict[str, Any]]:
"""Lista las categorías de un modelo"""
response = requests.get(
f"{self.base_url}/v1/models/{model_id}/categories",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def create_category(
self,
model_id: int,
name: str,
description: str,
order_number: int
) -> Dict[str, Any]:
"""Crea una categoría en un modelo"""
response = requests.post(
f"{self.base_url}/v1/models/{model_id}/categories",
headers=self._headers(),
json={
"name": name,
"description": description,
"order_number": order_number
}
)
response.raise_for_status()
return response.json()
# ==================== MODEL VARIABLES ====================
def list_variables(self, model_id: int) -> List[Dict[str, Any]]:
"""Lista las variables de un modelo"""
response = requests.get(
f"{self.base_url}/v1/models/{model_id}/variables",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def create_variable(
self,
model_id: int,
key: str,
readable_name: str,
description: str,
var_type: str,
weight: int,
category_id: int,
required: bool = True
) -> Dict[str, Any]:
"""Crea una variable en un modelo"""
response = requests.post(
f"{self.base_url}/v1/models/{model_id}/variables",
headers=self._headers(),
json={
"key": key,
"readable_name": readable_name,
"description": description,
"type": var_type,
"weight": weight,
"category_id": category_id,
"required": required
}
)
response.raise_for_status()
return response.json()
# ==================== MODEL METADATA ====================
def list_metadata(self, model_id: int) -> List[Dict[str, Any]]:
"""Lista los campos de metadata de un modelo"""
response = requests.get(
f"{self.base_url}/v1/models/{model_id}/metadata",
headers=self._headers()
)
response.raise_for_status()
return response.json()
def create_metadata(
self,
model_id: int,
key: str,
readable_name: str,
meta_type: str,
grouping_field: bool = False
) -> Dict[str, Any]:
"""Crea un campo de metadata en un modelo"""
response = requests.post(
f"{self.base_url}/v1/models/{model_id}/metadata",
headers=self._headers(),
json={
"key": key,
"readable_name": readable_name,
"type": meta_type,
"grouping_field": grouping_field
}
)
response.raise_for_status()
return response.json()
# ==================== STATISTICS ====================
def get_basic_stats(
self,
start_date: str,
end_date: str,
model_name: str
) -> Dict[str, Any]:
"""Obtiene estadísticas básicas"""
response = requests.get(
f"{self.base_url}/v1/stats/basic",
headers=self._headers(),
params={
"start_date": start_date,
"end_date": end_date,
"model_name": model_name
}
)
response.raise_for_status()
return response.json()
# ==================== EJEMPLO DE USO ====================
if __name__ == "__main__":
# Inicializar cliente (usa variables de entorno)
client = NeuracallClient()
# Listar modelos disponibles
print("Modelos disponibles:")
models = client.list_models()
for model in models:
print(f" - {model['name']} (ID: {model['id']})")
# Crear análisis
print("\nCreando análisis...")
analysis = client.create_analysis(
audio_path="llamada.mp3",
external_id="CALL-2024-001",
agent_id="AGT-001",
agent_name="Juan Perez",
model_name=models[0]["name"]
)
print(f"Análisis creado: {analysis['id']}")
print(f"Estado: {analysis['status']}")
# Esperar a que complete
print("\nEsperando resultado...")
result = client.wait_for_completion(analysis["id"])
# Mostrar resultados
print(f"\n=== RESULTADO ===")
print(f"NeuraScore: {result['score_percentage']}%")
print(f"Resumen: {result['summary']}")
if result.get("insights"):
print("\nInsights:")
for i, insight in enumerate(result["insights"], 1):
print(f" {i}. {insight}")
if result.get("keywords"):
print(f"\nKeywords: {', '.join(result['keywords'])}")
Uso Rápido
from neuracall_client import NeuracallClient
client = NeuracallClient()
# Analizar una llamada
result = client.create_analysis(
audio_path="llamada.mp3",
external_id="CALL-001",
agent_id="AGT-001",
agent_name="Juan Perez",
model_name="Evaluación Servicio"
)
# Esperar y obtener resultados
completed = client.wait_for_completion(result["id"])
print(f"Score: {completed['score_percentage']}%")
Manejo de Errores
import requests
try:
result = client.create_analysis(...)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
print("Error de autenticación")
elif e.response.status_code == 400:
print(f"Datos invalidos: {e.response.json()}")
else:
print(f"Error HTTP: {e}")
except Exception as e:
print(f"Error: {e}")
Gestión de Modelos
Crear un Modelo Completo
from neuracall_client import NeuracallClient
client = NeuracallClient()
# 1. Crear el modelo base
model = client.create_model(
name="Evaluación Ventas Q1",
description="Modelo para evaluar llamadas de ventas",
prompt="Evalúa la llamada considerando: saludo, identificación de necesidades, presentación y cierre."
)
model_id = model["id"]
print(f"Modelo creado: {model['name']} (ID: {model_id})")
# 2. Crear categorías
categories_data = [
{"name": "Apertura", "description": "Saludo e identificación", "order_number": 1},
{"name": "Descubrimiento", "description": "Identificación de necesidades", "order_number": 2},
{"name": "Presentación", "description": "Exposición de la solución", "order_number": 3},
{"name": "Cierre", "description": "Confirmación y siguientes pasos", "order_number": 4}
]
categories = {}
for cat_data in categories_data:
cat = client.create_category(
model_id=model_id,
name=cat_data["name"],
description=cat_data["description"],
order_number=cat_data["order_number"]
)
categories[cat["name"]] = cat["id"]
print(f" Categoría creada: {cat['name']} (ID: {cat['id']})")
# 3. Crear variables
variables_data = [
# Apertura (20 puntos)
{"key": "greeting", "readable_name": "Saludo", "description": "Saludo cordial y profesional",
"type": "INTEGER", "weight": 10, "category": "Apertura"},
{"key": "identification", "readable_name": "Identificación", "description": "Se identificó correctamente",
"type": "INTEGER", "weight": 10, "category": "Apertura"},
# Descubrimiento (25 puntos)
{"key": "open_questions", "readable_name": "Preguntas Abiertas", "description": "Usó preguntas abiertas",
"type": "INTEGER", "weight": 15, "category": "Descubrimiento"},
{"key": "active_listening", "readable_name": "Escucha Activa", "description": "Demostró escucha activa",
"type": "INTEGER", "weight": 10, "category": "Descubrimiento"},
# Presentación (30 puntos)
{"key": "benefits", "readable_name": "Presentación de Beneficios", "description": "Presentó beneficios claramente",
"type": "INTEGER", "weight": 15, "category": "Presentación"},
{"key": "objections", "readable_name": "Manejo de Objeciones", "description": "Manejó objeciones efectivamente",
"type": "INTEGER", "weight": 15, "category": "Presentación"},
# Cierre (25 puntos)
{"key": "proposal", "readable_name": "Propuesta Clara", "description": "Hizo una propuesta clara",
"type": "INTEGER", "weight": 10, "category": "Cierre"},
{"key": "next_steps", "readable_name": "Próximos Pasos", "description": "Confirmó los próximos pasos",
"type": "INTEGER", "weight": 15, "category": "Cierre"},
# Variable de extracción (sin peso)
{"key": "product_interest", "readable_name": "Producto de Interés", "description": "Producto mencionado",
"type": "STRING", "weight": 0, "category": "Descubrimiento", "required": False}
]
for var_data in variables_data:
var = client.create_variable(
model_id=model_id,
key=var_data["key"],
readable_name=var_data["readable_name"],
description=var_data["description"],
var_type=var_data["type"],
weight=var_data["weight"],
category_id=categories[var_data["category"]],
required=var_data.get("required", True)
)
print(f" Variable creada: {var['readable_name']} (peso: {var['weight']})")
# 4. Crear campos de metadata
metadata_fields = [
{"key": "campaign", "readable_name": "Campaña", "type": "STRING", "grouping_field": True},
{"key": "product", "readable_name": "Producto", "type": "STRING", "grouping_field": True},
{"key": "region", "readable_name": "Región", "type": "STRING", "grouping_field": True}
]
for meta_data in metadata_fields:
meta = client.create_metadata(
model_id=model_id,
key=meta_data["key"],
readable_name=meta_data["readable_name"],
meta_type=meta_data["type"],
grouping_field=meta_data["grouping_field"]
)
print(f" Metadata creada: {meta['readable_name']} (agrupación: {meta['grouping_field']})")
print(f"\nModelo '{model['name']}' configurado completamente!")
Listar Configuración de un Modelo
# Obtener toda la configuración de un modelo
model_id = 15
model = client.get_model(model_id)
print(f"Modelo: {model['name']}")
categories = client.list_categories(model_id)
print(f"\nCategorías ({len(categories)}):")
for cat in categories:
print(f" - {cat['name']} (orden: {cat['order_number']})")
variables = client.list_variables(model_id)
print(f"\nVariables ({len(variables)}):")
total_weight = 0
for var in variables:
print(f" - {var['readable_name']}: {var['type']} (peso: {var['weight']})")
total_weight += var['weight']
print(f" Total de pesos: {total_weight}")
metadata = client.list_metadata(model_id)
print(f"\nMetadata ({len(metadata)}):")
for meta in metadata:
grouping = "✓" if meta['grouping_field'] else "✗"
print(f" - {meta['readable_name']}: {meta['type']} (agrupación: {grouping})")
Manejo de Errores en Modelos
import requests
try:
# Intentar modificar un modelo con análisis existentes
client.create_variable(
model_id=15,
key="new_variable",
readable_name="Nueva Variable",
description="...",
var_type="INTEGER",
weight=10,
category_id=42
)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 409:
print("Error: No se puede modificar un modelo que ya tiene análisis asociados.")
print("Solución: Crea una nueva versión del modelo.")
elif e.response.status_code == 404:
print("Error: El modelo o categoría no existe.")
else:
print(f"Error HTTP: {e.response.status_code} - {e.response.json()}")
