Get Started
Before we begin, make sure you have an AssemblyAI account and an API key. You can sign up for an AssemblyAI account and get your API key from your dashboard. You will need to upgrade your account by adding a credit card to have access to LLM Gateway. Find more details on the current pricing in the AssemblyAI pricing page.Step-by-Step Instructions
Install the required packages:- Python
- JavaScript
pip install requests
npm install fs-extra
- Python
- JavaScript
import requests
import time
base_url = "https://api.assemblyai.com"
headers = {
"authorization": "<YOUR_API_KEY>"
}
with open("./local_file.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload",
headers=headers,
data=f)
upload_url = response.json()["upload_url"]
data = {
"audio_url": upload_url, # You can also use a URL to an audio or video file on the web
"speech_models": ["universal-3-pro"],
"redact_pii": True,
"redact_pii_policies": ["person_name", "organization", "occupation"],
"redact_pii_sub": "hash"
}
url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)
transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id
print(f"Transcript ID: {transcript_id}")
while True:
transcription_result = requests.get(polling_endpoint, headers=headers).json()
if transcription_result['status'] == 'completed':
print(transcription_result['text'])
break
elif transcription_result['status'] == 'error':
raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
else:
time.sleep(3)
import fs from "fs-extra";
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "<YOUR_API_KEY>",
};
const audioData = await fs.readFile("./local_file.mp3");
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const uploadUrl = uploadResponse.upload_url;
const data = {
audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
speech_models: ["universal-3-pro"],
redact_pii: true,
redact_pii_policies: ["person_name", "organization", "occupation"],
redact_pii_sub: "hash",
};
const url = `${baseUrl}/v2/transcript`;
res = await fetch(url, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptResponse = await res.json();
const transcriptId = transcriptResponse.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
console.log("Transcript ID:", transcriptId);
let transcriptionResult;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
transcriptionResult = await res.json();
if (transcriptionResult.status === "completed") {
console.log(transcriptionResult.text);
break;
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
Two different methods of generating SOAP notes
Method 1: Complete SOAP Note Generation
This method uses LLM Gateway to generate the entire SOAP note in one request. The prompt includes context about the audio file, a specific format for the SOAP note, and detailed instructions for each section.- Python
- JavaScript
prompt = """
Generate a SOAP note summary based on the following doctor-patient appointment transcript.
Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted.
Format the response as follows:
Subjective
This is typically the shortest section (only 2-3 sentences) and it describes the patient's affect, as the professional sees it. This information is all subjective (it isn't measureable).
- Include information that may have affected the patient's performance, such as if they were sick, tired, attentive, distractible, etc.
- Was the patient on time or did they come late?
- May include a quote of something the patient said, or how they reported feeling
Objective
This section includes factual, measurable, and objective information. This may include:
- Direct patient quotes
- Measurements
- Data on patient performance
Assessment
This section should be the meat of the SOAP note. It contains a narrative of what actually happened during the session. There may be information regarding:
- Whether improvements have been made since the last session
- Any potential barriers to success
- Clinician's interpretation of the results of the session
Plan
This is another short section that states the plan for future sessions. In most settings, this section may be bulleted
"""
# Send to LLM Gateway
llm_gateway_data = {
"model": "claude-sonnet-4-5-20250929",
"messages": [
{"role": "user", "content": f"{prompt}\n\n{{{{ transcript }}}}"}
],
"transcript_id": transcript_id,
"max_tokens": 2000
}
response = requests.post(
"https://llm-gateway.assemblyai.com/v1/chat/completions",
headers=headers,
json=llm_gateway_data
)
result = response.json()["choices"][0]["message"]["content"]
print(result.strip())
const prompt = `
Generate a SOAP note summary based on the following doctor-patient appointment transcript.
Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted.
Format the response as follows:
Subjective
This is typically the shortest section (only 2-3 sentences) and it describes the patient's affect, as the professional sees it. This information is all subjective (it isn't measureable).
- Include information that may have affected the patient's performance, such as if they were sick, tired, attentive, distractible, etc.
- Was the patient on time or did they come late?
- May include a quote of something the patient said, or how they reported feeling
Objective
This section includes factual, measurable, and objective information. This may include:
- Direct patient quotes
- Measurements
- Data on patient performance
Assessment
This section should be the meat of the SOAP note. It contains a narrative of what actually happened during the session. There may be information regarding:
- Whether improvements have been made since the last session
- Any potential barriers to success
- Clinician's interpretation of the results of the session
Plan
This is another short section that states the plan for future sessions. In most settings, this section may be bulleted
`;
// Send to LLM Gateway
const llmGatewayData = {
model: "claude-sonnet-4-5-20250929",
messages: [
{ role: "user", content: `${prompt}\n\n{{ transcript }}` },
],
transcript_id: transcriptId,
max_tokens: 2000,
};
let res = await fetch("https://llm-gateway.assemblyai.com/v1/chat/completions", {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(llmGatewayData),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const result = response.choices[0].message.content;
console.log(result.trim());
Method 2: Section-by-Section Generation
This method generates each section of the SOAP note separately using LLM Gateway. This makes it easy to regenerate one or more sections individually if needed. Each section is generated with a specific prompt tailored to that part of the SOAP note.- Python
- JavaScript
# Define questions for each SOAP section
questions = [
{
"section": "Subjective",
"question": "What are the patient's current symptoms or concerns?",
"context": "Gather information about the patient's subjective experience. Example: The patient reports experiencing persistent headaches and dizziness.",
"format": "<patient's symptoms or concerns>, [exact quote from patient]"
},
{
"section": "Objective",
"question": "What are the measurable and observable findings from the examination?",
"context": "Collect data on the patient's objective signs and measurements. Example: The examination reveals an elevated body temperature and increased heart rate.",
"format": "<measurable and observable findings>"
},
{
"section": "Assessment",
"question": "Based on the patient's history and examination, what is your assessment or diagnosis?",
"context": "Formulate a professional assessment based on the gathered information. Example: Based on the patient's symptoms, examination, and medical history, the preliminary diagnosis is migraine.",
"format": "<assessment or diagnosis>"
},
{
"section": "Plan",
"question": "What is the plan of action or treatment for the patient?",
"context": "Outline the intended course of action or treatment. Example: The treatment plan includes prescribing medication, recommending rest, and scheduling a follow-up appointment in two weeks.",
"format": "<plan of action or treatment>, [exact quote from provider]"
}
]
# Process each section
for q in questions:
prompt = f"""
{q['question']}
Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted. {q['context']}
Answer Format: {q['format']}
"""
llm_gateway_data = {
"model": "claude-sonnet-4-5-20250929",
"messages": [
{"role": "user", "content": f"{prompt}\n\n{{{{ transcript }}}}"}
],
"transcript_id": transcript_id,
"max_tokens": 1000
}
response = requests.post(
"https://llm-gateway.assemblyai.com/v1/chat/completions",
headers=headers,
json=llm_gateway_data
)
result = response.json()["choices"][0]["message"]["content"]
print(f"{q['section']}: {q['question']}")
print(result.strip())
print()
// Define questions for each SOAP section
const questions = [
{
section: "Subjective",
question: "What are the patient's current symptoms or concerns?",
context: "Gather information about the patient's subjective experience. Example: The patient reports experiencing persistent headaches and dizziness.",
format: "<patient's symptoms or concerns>, [exact quote from patient]",
},
{
section: "Objective",
question: "What are the measurable and observable findings from the examination?",
context: "Collect data on the patient's objective signs and measurements. Example: The examination reveals an elevated body temperature and increased heart rate.",
format: "<measurable and observable findings>",
},
{
section: "Assessment",
question: "Based on the patient's history and examination, what is your assessment or diagnosis?",
context: "Formulate a professional assessment based on the gathered information. Example: Based on the patient's symptoms, examination, and medical history, the preliminary diagnosis is migraine.",
format: "<assessment or diagnosis>",
},
{
section: "Plan",
question: "What is the plan of action or treatment for the patient?",
context: "Outline the intended course of action or treatment. Example: The treatment plan includes prescribing medication, recommending rest, and scheduling a follow-up appointment in two weeks.",
format: "<plan of action or treatment>, [exact quote from provider]",
},
];
// Process each section
for (const q of questions) {
const prompt = `
${q.question}
Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted. ${q.context}
Answer Format: ${q.format}
`;
const llmGatewayData = {
model: "claude-sonnet-4-5-20250929",
messages: [
{ role: "user", content: `${prompt}\n\n{{ transcript }}` },
],
transcript_id: transcriptId,
max_tokens: 1000,
};
let res = await fetch("https://llm-gateway.assemblyai.com/v1/chat/completions", {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(llmGatewayData),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const result = response.choices[0].message.content;
console.log(`${q.section}: ${q.question}`);
console.log(result.trim());
console.log();
}