Come fornire uno strumento di trascrizione a un agente IA
Puoi racchiudere le due chiamate all’API di KolWrite in un unico strumento chiamato transcribe_media. In questa pagina trovi la definizione pronta per il tool-use di Anthropic e il function-calling di OpenAI, la funzione Python che esegue il lavoro, un ciclo di esecuzione essenziale e una breve regola da aggiungere a AGENTS.md o CLAUDE.md per istruire gli assistenti di programmazione.
Serve davvero definire uno strumento?
Se il tuo agente può eseguire comandi di shell (Claude Code, Codex CLI, Cursor, Windsurf), non gli serve uno schema: esegue curl o Python, e le istruzioni di agent-instructions.md gli dicono come. Una definizione di strumento serve per gli agenti che costruisci con un’API e un ciclo di strumenti, o per i framework che chiamano funzioni.
Definizione dello strumento per Anthropic (tool-use)
{
"name": "transcribe_media",
"description": "Transcribe an audio or video file with the KolWrite API. Returns timed text. Use output_format \"json\" for word timestamps and speakers, \"srt\" for subtitles, \"txt\" for plain text. Billed per second of audio.",
"input_schema": {
"type": "object",
"properties": {
"path_or_url": { "type": "string", "description": "Local file path or a public URL of an audio or video file." },
"model": { "type": "string", "enum": ["base", "oracle_mini", "oracle", "oracle_pro", "oracle_max"], "description": "Default oracle. base is cheapest for clear audio; translate_to needs an Oracle model." },
"language": { "type": "string", "description": "Language code such as en, he, ar, es, or auto to detect." },
"translate_to": { "type": "string", "description": "Language code to translate into (Oracle models only)." },
"output_format": { "type": "string", "enum": ["json", "txt", "srt"] },
"word_timestamps": { "type": "boolean", "description": "Word times in json. For srt, false gives one cue per segment." },
"include_diarization": { "type": "boolean", "description": "Label who is speaking." },
"num_speakers": { "type": "integer", "minimum": 1 }
},
"required": ["path_or_url"]
}
}
Definizione dello strumento per OpenAI (function-calling)
{
"type": "function",
"function": {
"name": "transcribe_media",
"description": "Transcribe an audio or video file with the KolWrite API. Returns timed text. Use output_format \"json\" for word timestamps and speakers, \"srt\" for subtitles, \"txt\" for plain text. Billed per second of audio.",
"parameters": {
"type": "object",
"properties": {
"path_or_url": { "type": "string", "description": "Local file path or a public URL of an audio or video file." },
"model": { "type": "string", "enum": ["base", "oracle_mini", "oracle", "oracle_pro", "oracle_max"] },
"language": { "type": "string", "description": "Language code such as en, he, ar, es, or auto to detect." },
"translate_to": { "type": "string", "description": "Language code to translate into (Oracle models only)." },
"output_format": { "type": "string", "enum": ["json", "txt", "srt"] },
"word_timestamps": { "type": "boolean" },
"include_diarization": { "type": "boolean" },
"num_speakers": { "type": "integer", "minimum": 1 }
},
"required": ["path_or_url"]
}
}
}
Entrambi i formati usano lo stesso JSON Schema per i parametri. L’elenco enum contiene i modelli attuali, mentre core ed edge appartengono alla generazione precedente.
La funzione che esegue lo strumento
Questa funzione carica il file locale, avvia la trascrizione, attende il completamento e restituisce una risposta sintetica. Quando viene richiesto il formato JSON, la funzione salva l’output completo su disco e passa al modello solo le righe numerate: in una registrazione lunga, infatti, l’elenco di tutte le singole parole occuperebbe molto più contesto di quanto serva davvero all’LLM.
kolwrite.py
# kolwrite.py — three small functions around the KolWrite REST API
import os, time, requests
API = "https://app.kolwrite.com"
HEADERS = {"x-api-key": os.environ["KOLWRITE_API_KEY"]}
def upload(path):
"""Upload a local file (up to 100 MiB) and return a URL the API can read."""
name = os.path.basename(path)
form = requests.post(f"{API}/upload", headers=HEADERS, json={"filename": name}, timeout=30)
form.raise_for_status()
form = form.json()
with open(path, "rb") as media:
# No x-api-key on this request: it goes to the storage address.
sent = requests.post(form["uploadUrl"], data=form["uploadFields"],
files={"file": (name, media)}, timeout=600)
sent.raise_for_status()
return form["fileUrl"]
def transcribe(audio_url, timeout_s=3600, **options):
"""Start a job, wait for it, return the result: a dict for json, a string for srt and txt."""
body = {"audio_url": audio_url, "model": "oracle", **options}
job = requests.post(f"{API}/transcribe", headers=HEADERS, json=body, timeout=30)
job.raise_for_status()
job_id = job.json()["jobId"]
deadline = time.time() + timeout_s
while time.time() < deadline:
time.sleep(5)
reply = requests.get(f"{API}/transcribe/{job_id}", headers=HEADERS, timeout=30)
reply.raise_for_status()
reply = reply.json()
if reply["status"] == "COMPLETED":
return reply["result"]
if reply["status"] == "FAILED":
raise RuntimeError(reply.get("error", "transcription failed"))
raise TimeoutError(f"job {job_id} did not finish in {timeout_s} seconds")
tool.py
# tool.py — run a transcribe_media call for the model and keep the reply small
import json
from kolwrite import upload, transcribe # the helper from the video-editing guide
def numbered_line(number, segment):
who = f'{segment["speaker"]}: ' if segment.get("speaker") else ""
return f'S{number} [{segment["start"]:.1f}-{segment["end"]:.1f}] {who}{segment["text"]}'
def run_transcribe_media(path_or_url, output_format="json", **options):
url = path_or_url if path_or_url.startswith(("http://", "https://")) else upload(path_or_url)
result = transcribe(url, output_format=output_format, **options)
if output_format != "json":
return result # srt and txt are already strings
# Long recordings: save the full JSON and hand the model numbered lines, not 500 KB of words.
with open("transcript.json", "w", encoding="utf-8") as out:
json.dump(result, out, ensure_ascii=False)
lines = [numbered_line(i, s) for i, s in enumerate(result["segments"])]
return "Full JSON saved to transcript.json (words[] has word times).\n" + "\n".join(lines)
Un ciclo di strumenti minimo (Anthropic Messages API)
# loop.py — Anthropic Messages API tool loop around run_transcribe_media
import anthropic
from tool import run_transcribe_media
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
TOOLS = [...] # the transcribe_media definition above
messages = [{"role": "user", "content": "Transcribe interview.mp3 and list the questions asked, with times."}]
while True:
reply = client.messages.create(model="YOUR_MODEL", max_tokens=2000, tools=TOOLS, messages=messages)
messages.append({"role": "assistant", "content": reply.content})
if reply.stop_reason != "tool_use":
print("".join(block.text for block in reply.content if block.type == "text"))
break
results = []
for block in reply.content:
if block.type == "tool_use" and block.name == "transcribe_media":
results.append({"type": "tool_result", "tool_use_id": block.id,
"content": run_transcribe_media(**block.input)})
messages.append({"role": "user", "content": results})
Sostituisci YOUR_MODEL con l’ID del modello che stai usando. Il ciclo continua a girare finché il modello non smette di invocare strumenti. La stessa funzione di esecuzione si può integrare in qualsiasi framework capace di chiamare codice Python.
Regola per i file AGENTS.md e CLAUDE.md
Inserisci queste righe nel file di progetto che il tuo agente di codice legge all’avvio, così in ogni sessione userà l’endpoint giusto, i formati corretti e gestirà bene la chiave:
## Transcription
For speech-to-text, subtitles and word timings use the KolWrite API (https://app.kolwrite.com).
Before writing code read https://console.kolwrite.com/agent-instructions.md and /llms-full.txt.
- Key: KOLWRITE_API_KEY in the environment, sent as the x-api-key header. Never print it or commit it.
- POST /transcribe {"audio_url", "model": "oracle", "output_format": "json"}, then poll GET /transcribe/{jobId}.
- Local files: POST /upload first and use fileUrl as audio_url. Extract audio from video with ffmpeg to stay under 100 MiB.
- Subtitles: output_format "srt" with "word_timestamps": false (one cue per segment). Formats are json, txt, srt only.
- Always send "model". Ask me before transcribing anything longer than one hour: it costs money.
Tenere sotto controllo i costi dell’agente
- La trascrizione si paga per ogni secondo di audio, a partire da 0,48 US$ all’ora con il modello
base. La regola qui sopra indica all'agente di chiedere prima di procedere con i file lunghi. - Metti i risultati in cache salvando il JSON accanto al file multimediale, così puoi riutilizzarlo invece di trascrivere tutto da capo.
- Scegli il modello meno costoso per quello che ti serve:
basese l'audio è pulito,oracleper una resa da produzione eoracle_minise devi anche tradurre. - L'account e la chiave API devono essere creati da una persona, perché un agente non può registrarsi da solo. Passagli la chiave tramite una variabile d'ambiente.
Domande e risposte
Esiste un SDK o un server MCP per KolWrite?
Al momento della scrittura non sono pubblicati né un pacchetto SDK né un server MCP. L’API è HTTPS e JSON; usa la definizione di strumento qui sopra, curl o Python direttamente, oppure genera un client da openapi.json.
Come faccio a far trascrivere un audio a Claude Code?
Metti la chiave in KOLWRITE_API_KEY, aggiungi la regola qui sopra a CLAUDE.md e chiedi la trascrizione. Claude Code chiama l’API REST con curl o Python seguendo agent-instructions.md.
Quale modello dovrebbe usare di default un agente?
Per l'audio di produzione conviene usare oracle. Se l'audio è pulito, base è l'opzione più economica, mentre oracle_mini è il modello meno costoso che include la traduzione. Specifica sempre il parametro model, altrimenti di default viene usato il vecchio modello core.
L'agente può crearsi da solo la chiave API?
No. Deve essere una persona a registrarsi su console.kolwrite.com, acquistare i crediti e generare la chiave. L'agente la legge semplicemente dalle variabili d'ambiente.