I recently built a small internal tool that ingests earnings call transcripts and product reviews, then returns a structured summary with sentiment and extracted entities. In this tutorial, I will walk through exactly that pipeline so you can adapt it to your own documents. The entire thing runs against Oxlo.ai using the OpenAI SDK, which means zero client library changes if you are already using OpenAI-compatible code.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK installed with:
pip install openai
Step 1: Configure the Oxlo.ai client
I keep my API key in an environment variable and initialize the client exactly as I would for OpenAI, just with Oxlo.ai's base URL.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.getenv("OXLO_API_KEY")
)
Step 2: Define the system prompt
LLMs are chatty by default. I force strict JSON and a fixed schema so downstream code never has to guess what it will receive.
SYSTEM_PROMPT = """You are a precise document analysis engine. Analyze the text provided by the user and return a single JSON object. Do not wrap the output in markdown code fences. Do not include any commentary outside the JSON.
Required JSON schema:
{
"summary": "Concise 2-3 sentence overview of the main points.",
"sentiment": "positive | neutral | negative",
"confidence": 0.0 to 1.0,
"key_entities": ["named people", "organizations", "products", "locations"],
"action_items": ["tasks or commitments explicitly mentioned"]
}
Rules:
- Infer nothing. Use only facts stated in the text.
- If the text contains no action items, return an empty array.
- Output only valid JSON."""
Step 3: Write the core analysis function
This function sends the full document to Llama 3.3 70B on Oxlo.ai with JSON mode enabled. Because Oxlo.ai charges a flat rate per request rather than per token, I can pass in long transcripts without the cost scaling with word count. See https://oxlo.ai/pricing for plan details.
import json
def analyze_document(text: str) -> dict:
# Cap raw character length to stay safely inside context windows
safe_text = text[:120000]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": safe_text},
],
response_format={"type": "json_object"},
temperature=0.2,
)
raw_output = response.choices[0].message.content
return json.loads(raw_output)
Step 4: Assemble the complete script
I wire the client, prompt, and function into a single file that accepts an optional file path. If no path is given, it runs against a built-in sample transcript so I can verify the schema instantly.
import os
import sys
import json
from pathlib import Path
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.getenv("OXLO_API_KEY")
)
SYSTEM_PROMPT = """You are a precise document analysis engine. Analyze the text provided by the user and return a single JSON object. Do not wrap the output in markdown code fences. Do not include any commentary outside the JSON.
Required JSON schema:
{
"summary": "Concise 2-3 sentence overview of the main points.",
"sentiment": "positive | neutral | negative",
"confidence": 0.0 to 1.0,
"key_entities": ["named people", "organizations", "products", "locations"],
"action_items": ["tasks or commitments explicitly mentioned"]
}
Rules:
- Infer nothing. Use only facts stated in the text.
- If the text contains no action items, return an empty array.
- Output only valid JSON."""
def analyze_document(text: str) -> dict:
safe_text = text[:120000]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": safe_text},
],
response_format={"type": "json_object"},
temperature=0.2,
)
return json.loads(response.choices[0].message.content)
SAMPLE_TEXT = """
Acme Corp Q3 Earnings Call Transcript
CEO Jane Doe: Revenue grew 12% year over year to $450M, driven by our new cloud infrastructure line.
However, supply chain constraints in APAC delayed two major deployments.
CFO John Smith: We are committing to a 15% headcount increase in engineering to address the backlog.
Customer churn remained flat at 2%. We expect Q4 margins to compress slightly due to rising steel prices.
"""
def main():
if len(sys.argv) > 1:
text = Path(sys.argv[1]).read_text(encoding="utf-8")
else:
text = SAMPLE_TEXT
result = analyze_document(text)
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()
Run it
Save the script as analyzer.py, set your key, and run it without arguments to verify the sample output.
$ export OXLO_API_KEY="sk-oxlo.ai-..."
$ python analyzer.py
{
"summary": "Acme Corp reported 12% year over year revenue growth to $450M driven by cloud infrastructure, though APAC supply chain delays affected deployments. Leadership committed to a 15% engineering headcount increase and noted flat customer churn, with expected Q4 margin compression due to rising steel prices.",
"sentiment": "neutral",
"confidence": 0.85,
"key_entities": ["Acme Corp", "Jane Doe", "John Smith", "APAC", "cloud infrastructure"],
"action_items": ["15% headcount increase in engineering"]
}
Once the sample looks correct, point it at any text file on disk.
$ python analyzer.py earnings_q3.txt
Next steps
Swap the model string to kimi-k2.6 if you need to process documents that exceed the context window of standard LLMs, or to deepseek-v3.2 if you are summarizing technical documentation with heavy code snippets. To productionize this, add a lightweight Pydantic model to validate the JSON schema before you persist results to a database or data lake.
Top comments (0)