Passa al contenuto principale

Esempi di integrazione

Flussi completi da adattare alla propria integrazione. Tutti gli esempi presuppongono una chiave API generata dalla console (si veda Manuale › Chiavi API) con gli scope necessari.

Configurazione​

# Variabili d'ambiente: non vanno salvate in chiaro nei repository
export ASKMEAI_HOST="https://ai.askme.it"
export ASKMEAI_API_KEY="amai_xxxxxxxxxxxxxxxx"
export ASKMEAI_SOURCE_APP="api_direct"

Intestazioni usate negli esempi:

  • X-Api-Key: $ASKMEAI_API_KEY (obbligatoria);
  • X-Source-App: $ASKMEAI_SOURCE_APP (facoltativa: attribuisce consumi e conversazioni all'integrazione; in sua assenza vale l'applicazione di origine della chiave);
  • Content-Type: application/json sulle richieste con corpo JSON;
  • X-External-Id: <identificativo> (facoltativa: riporta un identificativo del proprio sistema nei record di consumo).

1. Conversare con un agente​

Riferimento: Endpoint: Agenti, Chat e Conversazioni.

cURL​

curl -X POST "$ASKMEAI_HOST/api/v2/chat" \
-H "X-Api-Key: $ASKMEAI_API_KEY" \
-H "X-Source-App: $ASKMEAI_SOURCE_APP" \
-H "X-External-Id: ticket-9281" \
-H "Content-Type: application/json" \
-d '{
"agent_id": 54,
"message": "Di cosa si occupa Lascaux?",
"external_conversation_id": "ticket-9281",
"stream": false
}'

Python (httpx)​

import os

import httpx

client = httpx.Client(
base_url=os.environ["ASKMEAI_HOST"] + "/api/v2",
headers={
"X-Api-Key": os.environ["ASKMEAI_API_KEY"],
"X-Source-App": os.environ.get("ASKMEAI_SOURCE_APP", "api_direct"),
},
timeout=60.0,
)

resp = client.post(
"/chat",
json={
"agent_id": 54,
"message": "Di cosa si occupa Lascaux?",
"external_conversation_id": "ticket-9281",
"stream": False,
},
headers={"X-External-Id": "ticket-9281"},
)
resp.raise_for_status()
data = resp.json()
print(data["content"])
print("conversazione:", data["conversation_id"])

Node.js (fetch)​

const HOST = process.env.ASKMEAI_HOST;
const API_KEY = process.env.ASKMEAI_API_KEY;

const resp = await fetch(`${HOST}/api/v2/chat`, {
method: 'POST',
headers: {
'X-Api-Key': API_KEY,
'X-Source-App': 'api_direct',
'X-External-Id': 'ticket-9281',
'Content-Type': 'application/json',
},
body: JSON.stringify({
agent_id: 54,
message: 'Di cosa si occupa Lascaux?',
external_conversation_id: 'ticket-9281',
stream: false,
}),
});

if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);
const data = await resp.json();
console.log(data.content);

Il testo della risposta è nel campo content al primo livello; le fonti sono in rag_sources. Una nuova richiesta con lo stesso external_conversation_id prosegue la stessa conversazione.


2. Conversare in streaming (SSE)​

Con "stream": true la risposta è text/event-stream. Il testo arriva negli eventi content; lo stream termina con done. L'elenco completo degli eventi e dei codici di errore è in Endpoint: Agenti, Chat e Conversazioni.

Python (httpx)​

import json
import os

import httpx

with httpx.stream(
"POST",
os.environ["ASKMEAI_HOST"] + "/api/v2/chat",
headers={
"X-Api-Key": os.environ["ASKMEAI_API_KEY"],
"X-Source-App": "api_direct",
"Accept": "text/event-stream",
},
json={"agent_id": 54, "message": "Come posso contattare Lascaux?", "stream": True},
timeout=None,
) as resp:
resp.raise_for_status()
for raw in resp.iter_lines():
if not raw.startswith("data: "):
continue
event = json.loads(raw[len("data: "):])
if event["type"] == "content":
print(event["content"], end="", flush=True)
elif event["type"] == "error":
print(f"\n[errore {event.get('code')}] {event.get('error')}")
elif event["type"] == "done":
print()
break

Node.js (fetch)​

const resp = await fetch(`${process.env.ASKMEAI_HOST}/api/v2/chat`, {
method: 'POST',
headers: {
'X-Api-Key': process.env.ASKMEAI_API_KEY,
'X-Source-App': 'api_direct',
'Content-Type': 'application/json',
Accept: 'text/event-stream',
},
body: JSON.stringify({ agent_id: 54, message: 'Come posso contattare Lascaux?', stream: true }),
});

if (!resp.ok) throw new Error(`HTTP ${resp.status}`);

const decoder = new TextDecoder();
let buffer = '';
for await (const chunk of resp.body) {
buffer += decoder.decode(chunk, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const event = JSON.parse(line.slice('data: '.length));
if (event.type === 'content') process.stdout.write(event.content);
if (event.type === 'error') console.error(`\n[errore ${event.code}] ${event.error}`);
}
}

3. Elencare gli agenti​

Riferimento: Endpoint: Agenti, Chat e Conversazioni.

curl -G "$ASKMEAI_HOST/api/v2/agents" \
-H "X-Api-Key: $ASKMEAI_API_KEY" \
--data-urlencode "status=active" \
--data-urlencode "limit=20"

Risposta (estratto):

{
"items": [
{
"id": 54,
"name": "Assistente sito",
"model_provider": "openai",
"model_name": "gpt-5-mini",
"rag_config": { "enabled": true, "knowledge_base_ids": [10, 11, 12] },
"status": "active",
"version": 3
}
],
"total": 1,
"offset": 0,
"limit": 20
}

Per un'applicazione che deve solo proporre gli agenti con cui conversare è più adatto GET /chat/agents, che restituisce nome, descrizione, icona e variabili del prompt senza la configurazione.


4. Caricare un documento in una base di conoscenza​

Riferimento: Endpoint: Knowledge Base. Dopo il caricamento il documento va elaborato: solo i documenti in stato indexed vengono consultati dagli agenti.

import os

import httpx

client = httpx.Client(
base_url=os.environ["ASKMEAI_HOST"] + "/api/v2",
headers={"X-Api-Key": os.environ["ASKMEAI_API_KEY"], "X-Source-App": "api_direct"},
timeout=120.0,
)

with open("policy-resi.pdf", "rb") as fh:
resp = client.post(
"/knowledge-bases/12/documents/upload",
files={"file": ("policy-resi.pdf", fh, "application/pdf")},
)
resp.raise_for_status()
document = resp.json()

resp = client.post(f"/knowledge-bases/12/documents/{document['id']}/process")
resp.raise_for_status()
processed = resp.json()
if processed["status"] == "error":
print("Elaborazione non riuscita:", processed["error_message"])
else:
print(processed["status"], processed["chunk_count"], "frammenti")

Per aggiornare in seguito lo stesso documento senza cambiarne l'identificativo si usa POST /knowledge-bases/12/documents/{document_id}/replace.


5. Analisi di un PDF​

Riferimento: Endpoint: Analisi e Classificazione. Il PDF si invia in base64 in un corpo JSON; la risposta 202 contiene l'id del job, da interrogare fino allo stato completed o failed.

import base64
import os
import time

import httpx

client = httpx.Client(
base_url=os.environ["ASKMEAI_HOST"] + "/api/v2",
headers={"X-Api-Key": os.environ["ASKMEAI_API_KEY"], "X-Source-App": "api_direct"},
timeout=60.0,
)

with open("contratto.pdf", "rb") as fh:
pdf_b64 = base64.b64encode(fh.read()).decode("ascii")

job = client.post("/analysis/pdf", json={
"name": "Analisi contratto",
"filename": "contratto.pdf",
"file_content": pdf_b64,
"custom_prompt": "Elenca le clausole principali del contratto.",
}).json()

while True:
status = client.get(f"/analysis/{job['id']}/status").json()
if status["status"] in ("completed", "failed"):
break
time.sleep(2)

detail = client.get(f"/analysis/{job['id']}").json()
if detail["status"] == "completed":
print(detail["result"]["response"])
else:
print("Analisi non riuscita:", detail["error_message"])

In alternativa POST /analysis/pdf/sync attende il completamento e restituisce direttamente il risultato.


La classificazione avviene in due passi: si costruisce un catalogo dai propri esempi, poi lo si interroga con nuovi testi. Riferimento: Endpoint: Analisi e Classificazione.

6.1 Costruzione del catalogo (una tantum)​

curl -X POST "$ASKMEAI_HOST/api/v2/analysis/catalogs/build" \
-H "X-Api-Key: $ASKMEAI_API_KEY" \
-H "X-Source-App: $ASKMEAI_SOURCE_APP" \
-H "Content-Type: application/json" \
-d '{
"name": "Richieste assistenza",
"mode": "supervised",
"threshold": 0.6,
"pairs": [
{ "ticket": "Non riesco ad accedere al portale, password dimenticata", "label_path": ["Accesso"] },
{ "ticket": "Il mio abbonamento risulta scaduto ma ho pagato", "label_path": ["Fatturazione"] },
{ "ticket": "Come posso cambiare la lingua dell'\''assistente virtuale?", "label_path": ["Configurazione"] }
]
}'

La risposta 202 contiene l'id del catalogo. Lo stato si legge con:

curl "$ASKMEAI_HOST/api/v2/analysis/catalogs/$CATALOG_ID" \
-H "X-Api-Key: $ASKMEAI_API_KEY"

Quando status vale ready il catalogo è utilizzabile.

6.2 Classificazione di nuovi testi​

curl -X POST "$ASKMEAI_HOST/api/v2/analysis/catalogs/classify" \
-H "X-Api-Key: $ASKMEAI_API_KEY" \
-H "X-Source-App: $ASKMEAI_SOURCE_APP" \
-H "Content-Type: application/json" \
-d "{
\"catalog_id\": $CATALOG_ID,
\"texts\": [
\"Ho perso la password e non entro più\",
\"La fattura di settembre riporta un importo errato\"
],
\"top_n\": 3
}"

La risposta è sincrona e contiene per ogni testo i candidati migliori con similarity e verdict (strong, medium, weak, none).


7. Traduzione di testi​

Riferimento: Endpoint: Agenti, Chat e Conversazioni. Richiede la funzionalità translation attiva e il permesso translation.use.

curl -X POST "$ASKMEAI_HOST/api/v2/translation/translate-batch" \
-H "X-Api-Key: $ASKMEAI_API_KEY" \
-H "X-Source-App: $ASKMEAI_SOURCE_APP" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "id": "titolo", "text": "Politica di reso" },
{ "id": "testo", "text": "Il reso è gratuito entro 30 giorni dalla consegna." }
],
"source_lang": "it",
"target_lang": "en"
}'
{
"items": [
{ "id": "titolo", "translated_text": "Return policy" },
{ "id": "testo", "translated_text": "Returns are free within 30 days of delivery." }
],
"provider": "openai"
}

8. Ritrovare una conversazione tramite identificativo esterno​

Utile quando il sistema chiamante usa un proprio identificativo di conversazione. Riferimento: Endpoint: Agenti, Chat e Conversazioni.

curl "$ASKMEAI_HOST/api/v2/conversations/by-external-id/ticket-9281" \
-H "X-Api-Key: $ASKMEAI_API_KEY"

L'identificativo è quello inviato in external_conversation_id nel corpo di POST /chat. Per proseguire la conversazione è sufficiente inviare un nuovo POST /chat con lo stesso external_conversation_id.


Collection Postman​

Per esplorare le API da un'interfaccia grafica è disponibile una collection Postman pronta all'uso, con le richieste principali raggruppate nelle cartelle Agenti e Chat, Knowledge Base, Analisi e Traduzione, Amministrazione, e con il flusso di base già impostato: creare una base di conoscenza, aggiungere ed elaborare un documento, creare un agente, conversare, leggere la conversazione.

⬇ Collection Postman di Askme AI (download)

Importazione e configurazione​

  1. In Postman selezionare Import › File e scegliere il file .json scaricato: compare la collection Askme AI — API.
  2. Aprire la collection, scegliere la scheda Variables e impostare i valori nella colonna Current value:
VariabileValore
baseUrll'URL base della propria organizzazione, per esempio https://ai.askme.it/api/v2
apiKeyla chiave amai_<chiave>
sourceAppapi_direct (già impostato)
  1. Selezionare Save. L'intestazione X-Api-Key è configurata a livello di collection e viene applicata a tutte le richieste.

Alcune richieste salvano automaticamente gli identificativi generati (kb_id, document_id, agent_id, conversation_id, catalog_id, analysis_id) nelle variabili della collection, così i passi del flusso si concatenano senza copiare i valori a mano. Una guida passo passo del flusso, in Postman e in cURL, è nel Quickstart API.


Errori comuni​

CodiceCausaSoluzione
401X-Api-Key assente, incompleta, revocata o scadutaVerificare l'intestazione e il valore completo della chiave
403 con PERMISSION_DENIEDGli scope della chiave non coprono l'operazioneAggiungere lo scope indicato in permission da Impostazioni › Chiavi API
403 con FEATURE_FLAG_DISABLEDFunzionalità non attiva per l'organizzazioneRivolgersi al team Askme
422Corpo o parametri non validiLeggere il dettaglio di validazione nel campo detail
429Limite di frequenza della chiave o quota del piano superatiRispettare Retry-After quando presente e ripetere con attesa crescente

Buone pratiche​

  • Usare X-External-Id per correlare i log del proprio sistema con i record di consumo di Askme AI, ed external_conversation_id per ritrovare e proseguire le conversazioni.
  • Mantenere lo stesso X-Source-App per tutta l'integrazione.
  • In Python riutilizzare un httpx.Client per tutte le richieste invece di aprirne uno per chiamata.
  • Gestire 429 con attese crescenti e casuali, rispettando Retry-After quando presente.
  • Per volumi elevati, controllare periodicamente le quote residue con GET /quotas/usage.