We are building a meeting audio analyzer that transcribes recordings and extracts structured insights. It helps teams turn unstructured conversations into searchable summaries and action items without manual note taking. I will walk through the exact code I run in production.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK (
pip install openai) - An Oxlo.ai API key from https://portal.oxlo.ai
- A sample audio file. I use a 10-minute team standup recording in MP3 format.
Step 1: Transcribe the audio
I send the audio to Oxlo.ai's Whisper Large v3 endpoint. Oxlo.ai runs this with no cold starts, so the transcription starts immediately even on the first request of the day.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
audio_file = open("meeting.mp3", "rb")
transcription = client.audio.transcriptions.create(
model="whisper-large-v3",
file=audio_file,
response_format="text"
)
print(transcription)
audio_file.close()
Step 2: Define the analysis agent
I keep the system prompt in a separate constant so I can tune it without touching the rest of the pipeline. It forces the model to output the same five sections every time.
SYSTEM_PROMPT = """You are a precise meeting intelligence analyst.
Your job is to read a meeting transcript and produce a structured analysis with exactly these sections:
1. SUMMARY: A concise 2-3 sentence overview of what was discussed.
2. KEY DECISIONS: A bullet list of every decision made. If none, write "No decisions recorded."
3. ACTION ITEMS: A bullet list of tasks, each prefixed with an owner if mentioned.
4. SENTIMENT: A single sentence describing the overall tone (positive, neutral, concerned, etc.).
5. FOLLOW-UP QUESTIONS: Any open questions that need clarification in the next meeting.
Use clear headings. Do not invent information that is not in the transcript."""
Step 3: Run the analysis
I pass the transcript to Llama 3.3 70B through Oxlo.ai's chat completions endpoint. This model is fast and follows instruction formatting well for extraction tasks. Because Oxlo.ai uses flat per-request pricing, a long transcript costs the same as a short one. See https://oxlo.ai/pricing for details.
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Analyze this meeting transcript:\n\n{transcription}"},
],
)
analysis = response.choices[0].message.content
print(analysis)
Step 4: Structured output with JSON mode
If you want to feed these results into a database or dashboard, JSON mode keeps the shape predictable. We repeat the call with response_format set to json_object and a tighter prompt. I switch to Kimi K2.6 here because it handles long context and structured reasoning well.
JSON_PROMPT = SYSTEM_PROMPT + """
Output strictly valid JSON with these keys:
- summary (string)
- decisions (array of strings)
- action_items (array of strings)
- sentiment (string)
- follow_up_questions (array of strings)
Do not include markdown formatting outside the JSON."""
response = client.chat.completions.create(
model="kimi-k2.6",
messages=[
{"role": "system", "content": JSON_PROMPT},
{"role": "user", "content": f"Analyze this meeting transcript:\n\n{transcription}"},
],
response_format={"type": "json_object"},
)
import json
structured = json.loads(response.choices[0].message.content)
print(json.dumps(structured, indent=2))
Run it
Putting the pieces together, here is the full script and the output it produces on a sample recording.
from openai import OpenAI
import json
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
# 1. Transcribe
with open("meeting.mp3", "rb") as f:
transcript = client.audio.transcriptions.create(
model="whisper-large-v3",
file=f,
response_format="text"
)
# 2. Analyze
SYSTEM_PROMPT = """You are a precise meeting intelligence analyst.
Your job is to read a meeting transcript and produce a structured analysis with exactly these sections:
1. SUMMARY: A concise 2-3 sentence overview of what was discussed.
2. KEY DECISIONS: A bullet list of every decision made. If none, write "No decisions recorded."
3. ACTION ITEMS: A bullet list of tasks, each prefixed with an owner if mentioned.
4. SENTIMENT: A single sentence describing the overall tone (positive, neutral, concerned, etc.).
5. FOLLOW-UP QUESTIONS: Any open questions that need clarification in the next meeting.
Use clear headings. Do not invent information that is not in the transcript."""
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Analyze this meeting transcript:\n\n{transcript}"},
],
)
print("=== ANALYSIS ===")
print(response.choices[0].message.content)
Example output:
=== ANALYSIS ===
SUMMARY: The product team reviewed Q3 roadmap priorities and discussed latency issues in the ingestion pipeline.
KEY DECISIONS:
- Delay the analytics dashboard by one sprint to focus on pipeline stability.
- Adopt Oxlo.ai for inference to reduce cost on long-context audio summarization jobs.
ACTION ITEMS:
- Sarah: Profile the bottleneck in the audio preprocessor by Friday.
- Mike: Draft revised timeline and share in Slack.
SENTIMENT: Cautiously optimistic with focused urgency.
FOLLOW-UP QUESTIONS:
- What is the exact latency target for the 99th percentile?
- Do we have budget approval for the additional GPU nodes?
Next steps
Add speaker diarization by preprocessing with a library like pyannote.audio, then tag transcript segments with speaker names before sending them to the LLM. This turns a flat transcript into a per-speaker audit trail.
Batch process a folder of recordings and store the JSON output in SQLite or Postgres for full-text search across all your meetings. You can run this on a schedule with a small cron job or GitHub Action.
Top comments (0)