Market research teams still spend hours hand-coding open-ended survey responses. We will build a Python CLI tool that sends batches of customer feedback to an LLM, extracts sentiment scores, themes, and urgency flags, and returns a structured JSON report. It runs entirely on Oxlo.ai's request-based API, so analyzing a 500-word focus-group transcript costs the same as a one-sentence tweet.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
1. Configure the Oxlo.ai client
First, I verify that my environment can reach Oxlo.ai and that my key is active. I use the OpenAI SDK because Oxlo.ai is a drop-in replacement.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
# Verify connectivity
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": "Reply with OK"}],
max_tokens=5
)
print("API status:", response.choices[0].message.content)
2. Define the system prompt
Next, I write a strict system prompt that forces the model to return JSON with exactly the fields my downstream dashboard expects. I keep the instructions concrete to reduce hallucinated keys.
SYSTEM_PROMPT = """You are a market-research sentiment analyst.
Read the customer feedback and return a JSON object with exactly these keys:
- sentiment: one of Positive, Neutral, Negative
- score: integer from 1 to 10 where 10 is extremely positive
- themes: array of up to 3 themes mentioned, each 1 to 3 words
- urgency: boolean, true if the feedback implies churn risk or safety issue
- summary: one-sentence summary of the feedback
Rules:
- Be concise.
- Base scores only on the text provided.
- If the text is vague or off-topic, score it 5 and set sentiment Neutral.
"""
3. Build the analyzer function
Now I wrap the API call in a reusable function. I set response_format to JSON mode and keep temperature low so the scores stay consistent across reruns.
import json
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
SYSTEM_PROMPT = """You are a market-research sentiment analyst.
Read the customer feedback and return a JSON object with exactly these keys:
- sentiment: one of Positive, Neutral, Negative
- score: integer from 1 to 10 where 10 is extremely positive
- themes: array of up to 3 themes mentioned, each 1 to 3 words
- urgency: boolean, true if the feedback implies churn risk or safety issue
- summary: one-sentence summary of the feedback
Rules:
- Be concise.
- Base scores only on the text provided.
- If the text is vague or off-topic, score it 5 and set sentiment Neutral.
"""
def analyze_feedback(text: str, model: str = "llama-3.3-70b") -> dict:
"""Send feedback text to Oxlo.ai and return structured sentiment data."""
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
temperature=0.1,
)
return json.loads(response.choices[0].message.content)
# Sanity check
sample = "I love the new dashboard, but customer support never answers emails."
print(json.dumps(analyze_feedback(sample), indent=2))
4. Process a batch of responses
Real market research comes in batches. I loop over a list of survey responses, call the analyzer for each, and sleep briefly between requests to stay polite. Because Oxlo.ai charges per request, not per token, I do not need to worry about the cost of longer responses.
import json
import os
import time
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
SYSTEM_PROMPT = """You are a market-research sentiment analyst.
Read the customer feedback and return a JSON object with exactly these keys:
- sentiment: one of Positive, Neutral, Negative
- score: integer from 1 to 10 where 10 is extremely positive
- themes: array of up to 3 themes mentioned, each 1 to 3 words
- urgency: boolean, true if the feedback implies churn risk or safety issue
- summary: one-sentence summary of the feedback
Rules:
- Be concise.
- Base scores only on the text provided.
- If the text is vague or off-topic, score it 5 and set sentiment Neutral.
"""
def analyze_feedback(text: str, model: str = "llama-3.3-70b") -> dict:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
temperature=0.1,
)
return json.loads(response.choices[0].message.content)
FEEDBACK_BATCH = [
"The product is amazing and saved me hours every week.",
"Terrible experience. The app crashes every time I open it.",
"It is okay. Nothing special but does the job.",
"Shipping was fast but the packaging was damaged.",
"I will cancel my subscription if the new pricing goes live.",
]
results = []
for item in FEEDBACK_BATCH:
result = analyze_feedback(item)
result["original"] = item
results.append(result)
time.sleep(0.5)
with open("sentiment_results.json", "w") as f:
json.dump(results, f, indent=2)
print(f"Processed {len(results)} responses. Saved to sentiment_results.json")
5. Aggregate and rank themes
Finally, I read the JSON file back and compute the metrics that matter to stakeholders: sentiment distribution, average score, and the most frequent themes. I also flag how many responses triggered the urgency boolean.
import json
from collections import Counter
with open("sentiment_results.json", "r") as f:
results = json.load(f)
sentiment_dist = Counter([r["sentiment"] for r in results])
avg_score = sum(r["score"] for r in results) / len(results)
all_themes = [theme for r in results for theme in r.get("themes", [])]
urgent_count = sum(1 for r in results if r.get("urgency"))
print("Sentiment distribution:", dict(sentiment_dist))
print(f"Average score: {avg_score:.1f} / 10")
print(f"Urgent items: {urgent_count}")
print("Top themes:", Counter(all_themes).most_common(5))
Run it
Save the script as sentiment_pipeline.py, set your key, and execute:
export OXLO_API_KEY="sk-..."
python sentiment_pipeline.py
Example output after the aggregation step looks like this:
Sentiment distribution: {'Positive': 1, 'Neutral': 1, 'Negative': 3}
Average score: 4.2 / 10
Urgent items: 2
Top themes: [('app crashes', 1), ('shipping speed', 1), ('packaging damage', 1), ('pricing concern', 1), ('time savings', 1)]
Wrap-up
You now have a working pipeline that turns raw feedback into structured metrics. Two concrete next steps: wire the script into a cron job or GitHub Action to process weekly survey exports automatically, or swap llama-3.3-70b for kimi-k2.6 or qwen-3-32b if you need stronger multilingual reasoning for international market research. For pricing details on running this at scale, see https://oxlo.ai/pricing.
Top comments (0)