DEV Community

shashank ms
shashank ms

Posted on

The Role of LLM in Social Media Analysis

We are going to build a social media monitoring agent that reads raw posts and extracts sentiment, topics, and urgency into structured JSON. It helps community managers and brand teams spot emerging issues without scrolling through hundreds of messages manually. Because the agent can process long threads or bulky post dumps in a single request, Oxlo.ai's flat per-request pricing keeps costs predictable no matter how verbose the input gets.

What you'll need

  • Python 3.10 or newer
  • The OpenAI SDK installed with pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai

Step 1: Connect and verify

Before we parse anything, we confirm the SDK can reach Oxlo.ai. I use Llama 3.3 70B here because it follows instructions reliably for structured tasks.

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": "Reply with exactly: Connection OK"},
    ],
)
print(response.choices[0].message.content)

Step 2: Define the schema and system prompt

Social data is noisy, so we lock the output to JSON. The prompt forces the model to return sentiment, dominant topics, urgency level, and a one-line summary.

SYSTEM_PROMPT = """
You are a social media analyst. Analyze the user-provided post and return ONLY a JSON object with this exact schema:

{
  "sentiment": "positive" | "neutral" | "negative",
  "urgency": "low" | "medium" | "high",
  "topics": ["topic1", "topic2"],
  "summary": "One-line summary of the post"
}

Rules:
- sentiment must be exactly one of the three allowed strings.
- urgency is high if the post contains a complaint about safety, billing, or a service outage.
- topics should be 1 to 3 concise keywords.
- Output ONLY raw JSON. No markdown fences, no explanations.
"""

Step 3: Analyze a single post

We wrap the API call in a function that sends raw text and parses the JSON response. Oxlo.ai supports JSON mode, so we add response_format to guarantee valid output.

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

def analyze_post(post_text: str) -> dict:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": post_text},
        ],
        response_format={"type": "json_object"},
    )
    raw = response.choices[0].message.content
    return json.loads(raw)

# Test
post = "Waited 2 hours for a delivery that never showed. Support line just rings forever. Extremely frustrated."
result = analyze_post(post)
print(json.dumps(result, indent=2))

Step 4: Batch process a feed and aggregate trends

In production you will have dozens of posts. We loop over them, collect structured results, and build local counters. Because Oxlo.ai charges a flat rate per request, not per token, you can feed long threads into a single analysis call without worrying about ballooning costs. See https://oxlo.ai/pricing for plan details.

from collections import Counter

raw_posts = [
    "Waited 2 hours for a delivery that never showed. Support line just rings forever.",
    "Loving the new dark mode update. Looks really clean on mobile.",
    "Dark mode is nice but the font is too small now. Please fix.",
    "Charged twice for my subscription this month. Need a refund ASAP.",
    "The API docs are amazing. Found exactly what I needed in seconds.",
]

analyses = [analyze_post(p) for p in raw_posts]

sentiment_counts = Counter(a["sentiment"] for a in analyses)
urgent_posts = [a for a in analyses if a["urgency"] == "high"]
top_topics = Counter(t for a in analyses for t in a["topics"]).most_common(3)

print("Sentiment distribution:", dict(sentiment_counts))
print("Urgent items:", len(urgent_posts))
print("Top topics:", top_topics)

Step 5: Generate the executive brief

Instead of reading every JSON blob, we pass the aggregated data back to the model to generate a short narrative summary. I switch to Qwen 3 32B here because its multilingual reasoning is useful when social feeds mix languages.

from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

def generate_brief(analyses: list[dict]) -> str:
    payload = {
        "sentiment_distribution": dict(Counter(a["sentiment"] for a in analyses)),
        "urgent_count": len([a for a in analyses if a["urgency"] == "high"]),
        "top_topics": [t[0] for t in Counter(t for a in analyses for t in a["topics"]).most_common(5)],
        "summaries": [a["summary"] for a in analyses],
    }

    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {
                "role": "system",
                "content": "You are a social media manager. Write a 3-sentence executive brief based on the provided JSON analytics. Be direct and actionable."
            },
            {"role": "user", "content": json.dumps(payload)},
        ],
    )
    return response.choices[0].message.content

brief = generate_brief(analyses)
print(brief)

Run it

Here is the complete script assembled. Drop in your key, run it, and you will get structured analyses followed by a manager-ready brief.

import json
from collections import Counter
from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

SYSTEM_PROMPT = """
You are a social media analyst. Analyze the user-provided post and return ONLY a JSON object with this exact schema:

{
  "sentiment": "positive" | "neutral" | "negative",
  "urgency": "low" | "medium" | "high",
  "topics": ["topic1", "topic2"],
  "summary": "One-line summary of the post"
}

Rules:
- sentiment must be exactly one of the three allowed strings.
- urgency is high if the post contains a complaint about safety, billing, or a service outage.
- topics should be 1 to 3 concise keywords.
- Output ONLY raw JSON. No markdown fences, no explanations.
"""

def analyze_post(post_text: str) -> dict:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": post_text},
        ],
        response_format={"type": "json_object"},
    )
    return json.loads(response.choices[0].message.content)

raw_posts = [
    "Waited 2 hours for a delivery that never showed. Support line just rings forever.",
    "Loving the new dark mode update. Looks really clean on mobile.",
    "Dark mode is nice but the font is too small now. Please fix.",
    "Charged twice for my subscription this month. Need a refund ASAP.",
    "The API docs are amazing. Found exactly what I needed in seconds.",
]

analyses = [analyze_post(p) for p in raw_posts]

def generate_brief(analyses: list[dict]) -> str:
    payload = {
        "sentiment_distribution": dict(Counter(a["sentiment"] for a in analyses)),
        "urgent_count": len([a for a in analyses if a["urgency"] == "high"]),
        "top_topics": [t[0] for t in Counter(t for a in analyses for t in a["topics"]).most_common(5)],
        "summaries": [a["summary"] for a in analyses],
    }
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": "You are a social media manager. Write a 3-sentence executive brief based on the provided JSON analytics. Be direct and actionable."},
            {"role": "user", "content": json.dumps(payload)},
        ],
    )
    return response.choices[0].message.content

print("=== Individual Analyses ===")
for a in analyses:
    print(json.dumps(a))

print("\n=== Executive Brief ===")
print(generate_brief(analyses))

Expected output:

=== Individual Analyses ===
{"sentiment": "negative", "urgency": "high", "topics": ["delivery", "support"], "summary": "Customer frustrated over missed delivery and unreachable support."}
{"sentiment": "positive", "urgency": "low", "topics": ["dark mode", "mobile"], "summary": "User praises new dark mode on mobile."}
{"sentiment": "neutral", "urgency": "medium", "topics": ["dark mode", "font size"], "summary": "User likes dark mode but requests larger font size."}
{"sentiment": "negative", "urgency": "high", "topics": ["billing", "refund"], "summary": "Customer reports double charge and demands refund."}
{"sentiment": "positive", "urgency": "low", "topics": ["documentation", "API"], "summary": "User compliments clear API documentation."}

=== Executive Brief ===
Sentiment is split, but two high-urgency billing and delivery complaints need immediate attention. Product should prioritize a font size toggle following dark mode feedback. Overall, documentation sentiment is strong and can be leveraged in upcoming marketing.

Wrap up and next steps

You now have a working agent that turns unstructured social noise into structured data and a readable brief. Two concrete ways to extend it:

First, wire the analyzer to a live platform firehose via webhooks and run it on a schedule so your dashboard updates in real time. Second, add vision support with Kimi K2.6 or Gemma 3 27B to parse screenshot memes and image-heavy posts that text-only models miss. Both models are available on Oxlo.ai with the same OpenAI-compatible client and flat per-request pricing.

Top comments (0)