What we are building
We are building a batch sentiment analysis tool that classifies customer feedback into positive, negative, or neutral categories, then aggregates the results into a summary report. This helps support teams and product managers process large volumes of text without maintaining brittle keyword lists. Oxlo.ai fits here because its request-based pricing does not scale with input length, so analyzing a paragraph-long rant costs the same as analyzing a one-line compliment.
What you will need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Initialize the client and verify connectivity
I start by importing the OpenAI SDK and pointing it at Oxlo.ai. A quick sanity check with Llama 3.3 70B confirms the endpoint and key are working.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Say hello"},
],
)
print(response.choices[0].message.content)
Step 2: Define the system prompt
I keep the instructions in a dedicated system prompt so the model returns strict JSON. This reduces noise in the user prompt and keeps the request payload clean.
SYSTEM_PROMPT = """You are a sentiment analysis engine. Analyze the user message and return a JSON object with exactly these keys:
- sentiment: one of "positive", "negative", or "neutral"
- confidence: a float between 0.0 and 1.0
- explanation: one sentence describing why you chose this sentiment
Return only valid JSON. Do not include markdown code fences."""
Step 3: Build the analysis function with JSON mode
I wrap the call in a helper that enables JSON mode. Using Llama 3.3 70B gives reliable instruction following, and JSON mode removes the need for fragile regex parsing.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
def analyze_sentiment(text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
)
raw = response.choices[0].message.content
return json.loads(raw)
Step 4: Process a batch of reviews
Next I feed a list of real customer reviews through the function. Because Oxlo.ai pricing is flat per request, the cost of this batch is simply the number of reviews, even if some reviews are long.
reviews = [
"The onboarding was smooth and the team was incredibly helpful. I was productive within an hour.",
"I waited three days for a response to a critical outage ticket. Completely unacceptable.",
"The product does what the documentation says. Nothing more, nothing less.",
"Love the new dashboard layout. Much easier to read on mobile now.",
"Billing is confusing. I was charged twice and support has not resolved it yet.",
]
results = [analyze_sentiment(r) for r in reviews]
Step 5: Aggregate and display a summary
Finally, I tally the sentiments and compute average confidence so the team can see both volume and model certainty at a glance.
from collections import Counter
sentiment_counts = Counter(r["sentiment"] for r in results)
avg_confidence = sum(r["confidence"] for r in results) / len(results)
print("Sentiment Summary")
print("-" * 20)
for sentiment, count in sentiment_counts.items():
print(f" {sentiment}: {count}")
print(f"Average confidence: {avg_confidence:.2f}")
print("\nDetailed results:")
for review, res in zip(reviews, results):
print(f"\nReview: {review[:50]}...")
print(f" -> {res['sentiment']} ({res['confidence']:.2f}): {res['explanation']}")
Run it
Save the script as sentiment.py, export your key, and execute it. The output should look something like this.
$ export OXLO_API_KEY="sk-oxlo.ai-..."
$ python sentiment.py
Sentiment Summary
--------------------
positive: 2
negative: 2
neutral: 1
Average confidence: 0.91
Detailed results:
Review: The onboarding was smooth and the team was incredibly...
-> positive (0.95): The user praises the onboarding experience and speed.
Review: I waited three days for a response to a critical outage...
-> negative (0.97): The user expresses frustration about a long wait during an outage.
Review: The product does what the documentation says. Nothing mo...
-> neutral (0.88): The statement is factual and lacks strong emotional language.
Review: Love the new dashboard layout. Much easier to read on mo...
-> positive (0.93): The user explicitly praises the new design and improved usability.
Review: Billing is confusing. I was charged twice and support ha...
-> negative (0.92): The user describes a billing error and unresolved support issue.
Next steps
Wire this function into a lightweight FastAPI endpoint so support webhooks can stream reviews in real time. If you are processing high volumes, move the loop to an async queue like Celery and upgrade to the Oxlo.ai Premium plan for priority queue access and higher daily limits.
For multilingual feedback, swap the model string to qwen-3-32b without changing any other code. You can view current request allowances at https://oxlo.ai/pricing.
For further actions, you may consider blocking this person and/or reporting abuse
