Faculytics Docs

Sentiment Worker

Batch sentiment analysis contract — request/response schemas, deployment, and versioning.

Source of Truth: src/modules/analysis/dto/sentiment-worker.dto.ts

Endpoint

POST {SENTIMENT_WORKER_URL}

Request

{
  "items": [
    {
      "submissionId": "uuid-string",
      "text": "The professor was very helpful and engaging."
    },
    {
      "submissionId": "uuid-string-2",
      "text": "Too fast. Couldn't keep up."
    }
  ],
  "metadata": {
    "pipelineId": "uuid-string",
    "runId": "uuid-string",
    "chunkIndex": 0,
    "chunkCount": 17
  },
  "vllmConfig": {
    "url": "https://vllm.internal.example/v1",
    "model": "llama-3.1-8b-instruct",
    "enabled": true
  }
}

Fields

FieldTypeRequiredDescription
itemsarrayYesArray of submissions to analyze
items[].submissionIdstringYesUnique submission identifier
items[].textstring (min 1)YesQualitative comment text
metadata.pipelineIdstringYesParent pipeline ID
metadata.runIdstringYesCurrent sentiment run ID
metadata.chunkIndexint (≥ 0)No0-based index of this chunk within the run (omitted on legacy single-batch dispatch)
metadata.chunkCountint (≥ 1)NoTotal chunks for this run
vllmConfigobjectNoWhen present + enabled=true, the worker should route through the vLLM URL/model below
vllmConfig.urlstring (https)If vllmConfigMust start with https:// (SSRF mitigation)
vllmConfig.modelstringIf vllmConfigModel identifier passed to vLLM
vllmConfig.enabledbooleanIf vllmConfigWhen false, worker may treat the request as if vllmConfig was omitted

Chunked Dispatch

The API splits each pipeline run into N chunks of SENTIMENT_CHUNK_SIZE (default 50) and sends one request per chunk. Workers should treat each chunk independently and return results only for the items in that request — counter-based completion tracking on the API side reassembles the run. See AI Inference Pipeline — Chunked Sentiment Dispatch.

Response

{
  "version": "1.0",
  "status": "completed",
  "results": [
    {
      "submissionId": "uuid-string",
      "positive": 0.85,
      "neutral": 0.1,
      "negative": 0.05
    },
    {
      "submissionId": "uuid-string-2",
      "positive": 0.05,
      "neutral": 0.15,
      "negative": 0.8
    }
  ],
  "completedAt": "2026-03-13T10:30:00.000Z"
}

Fields

FieldTypeRequiredDescription
versionstringYesWorker/model version identifier
statusenumYescompleted or failed
resultsarrayOn successPer-submission sentiment scores
results[].submissionIdstringYesMatches input submissionId
results[].positivenumber (0-1)YesPositive sentiment score
results[].neutralnumber (0-1)YesNeutral sentiment score
results[].negativenumber (0-1)YesNegative sentiment score
results[].servedByvllm | openaiNoWhich path actually served this item; persisted on SentimentResult.rawResult for provenance
errorstringOn failureError message when status is failed
completedAtISO datetimeYesProcessing completion timestamp

Error Response

{
  "version": "1.0",
  "status": "failed",
  "error": "Model inference failed: CUDA out of memory",
  "completedAt": "2026-03-13T10:30:00.000Z"
}

RunPod Envelope

When deployed on RunPod, the request and response are wrapped by RunPodBatchProcessor:

  • Request: Sent as { "input": <request body above> } to the RunPod /runsync endpoint.
  • Response: RunPod returns { "output": <response body above> } on completion. If the job exceeds the /runsync timeout (~30s), RunPod returns {"id":"...","status":"IN_QUEUE"} and the processor polls /status/{id} until done.
  • Auth: Authorization: Bearer <RUNPOD_API_KEY> header is added when RUNPOD_API_KEY is configured.

completedAt Format

Accepts any valid ISO 8601 datetime with timezone: both 2026-03-13T10:30:00.000Z and 2026-03-13T10:30:00.000+00:00 are valid.

Deployment

  • Platform: RunPod (serverless GPU)
  • Model: Multilingual sentiment classifier (positive/neutral/negative)
  • Batch size: Entire run in one request

Versioning

The version field in responses tracks the model/worker version. This is stored on the SentimentRun.workerVersion field for provenance tracking.