Generate SOAP Notes using LLM Gateway

The acronym SOAP stands for Subjective, Objective, Assessment, and Plan. This standardized method of documenting patient encounters allows providers to concisely record patient information. This guide walks through how to generate SOAP notes with AssemblyAI’s LLM Gateway, which provides access to multiple LLM providers through a unified API.

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:

$pip install requests

Set up your transcription with PII redaction enabled to protect patient information:

1import requests
2import time
3
4base_url = "https://api.assemblyai.com"
5
6headers = {
7 "authorization": "<YOUR_API_KEY>"
8}
9
10with open("./local_file.mp3", "rb") as f:
11 response = requests.post(base_url + "/v2/upload",
12 headers=headers,
13 data=f)
14
15upload_url = response.json()["upload_url"]
16
17data = {
18 "audio_url": upload_url, # You can also use a URL to an audio or video file on the web
19 "redact_pii": True,
20 "redact_pii_policies": ["person_name", "organization", "occupation"],
21 "redact_pii_sub": "hash"
22}
23
24url = base_url + "/v2/transcript"
25response = requests.post(url, json=data, headers=headers)
26
27transcript_id = response.json()['id']
28polling_endpoint = base_url + "/v2/transcript/" + transcript_id
29
30print(f"Transcript ID:", transcript_id)
31
32while True:
33 transcription_result = requests.get(polling_endpoint, headers=headers).json()
34
35 if transcription_result['status'] == 'completed':
36 print(transcription_result['text'])
37 break
38 elif transcription_result['status'] == 'error':
39 raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
40 else:
41 time.sleep(3)

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.

1prompt = """
2Generate a SOAP note summary based on the following doctor-patient appointment transcript.
3
4Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted.
5
6Format the response as follows:
7
8Subjective
9This 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).
10- Include information that may have affected the patient's performance, such as if they were sick, tired, attentive, distractible, etc.
11- Was the patient on time or did they come late?
12- May include a quote of something the patient said, or how they reported feeling
13
14Objective
15This section includes factual, measurable, and objective information. This may include:
16- Direct patient quotes
17- Measurements
18- Data on patient performance
19
20Assessment
21This 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:
22- Whether improvements have been made since the last session
23- Any potential barriers to success
24- Clinician's interpretation of the results of the session
25
26Plan
27This is another short section that states the plan for future sessions. In most settings, this section may be bulleted
28"""
29
30# Send to LLM Gateway
31llm_gateway_data = {
32 "model": "claude-sonnet-4-5-20250929",
33 "messages": [
34 {"role": "user", "content": f"{prompt}\n\nTranscript: {transcription_result['text']}"}
35 ],
36 "max_tokens": 2000
37}
38
39response = requests.post(
40 "https://llm-gateway.assemblyai.com/v1/chat/completions",
41 headers=headers,
42 json=llm_gateway_data
43)
44
45result = response.json()["choices"][0]["message"]["content"]
46print(result.strip())

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.

1# Define questions for each SOAP section
2questions = [
3 {
4 "section": "Subjective",
5 "question": "What are the patient's current symptoms or concerns?",
6 "context": "Gather information about the patient's subjective experience. Example: The patient reports experiencing persistent headaches and dizziness.",
7 "format": "<patient's symptoms or concerns>, [exact quote from patient]"
8 },
9 {
10 "section": "Objective",
11 "question": "What are the measurable and observable findings from the examination?",
12 "context": "Collect data on the patient's objective signs and measurements. Example: The examination reveals an elevated body temperature and increased heart rate.",
13 "format": "<measurable and observable findings>"
14 },
15 {
16 "section": "Assessment",
17 "question": "Based on the patient's history and examination, what is your assessment or diagnosis?",
18 "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.",
19 "format": "<assessment or diagnosis>"
20 },
21 {
22 "section": "Plan",
23 "question": "What is the plan of action or treatment for the patient?",
24 "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.",
25 "format": "<plan of action or treatment>, [exact quote from provider]"
26 }
27]
28
29# Process each section
30for q in questions:
31 prompt = f"""
32{q['question']}
33
34Context: This is a doctor appointment between patient and provider. The personal identification information has been redacted. {q['context']}
35
36Answer Format: {q['format']}
37"""
38
39 llm_gateway_data = {
40 "model": "claude-sonnet-4-5-20250929",
41 "messages": [
42 {"role": "user", "content": f"{prompt}\n\nTranscript: {transcription_result['text']}"}
43 ],
44 "max_tokens": 1000
45 }
46
47 response = requests.post(
48 "https://llm-gateway.assemblyai.com/v1/chat/completions",
49 headers=headers,
50 json=llm_gateway_data
51 )
52
53 result = response.json()["choices"][0]["message"]["content"]
54 print(f"{q['section']}: {q['question']}")
55 print(result.strip())
56 print()