Skip to content

Repository files navigation

Support Ticket Triage with DigitalOcean Inference

A small, production-minded demo that turns an incoming support ticket into a structured operations brief using DigitalOcean Serverless Inference.

The model summarizes the issue, assigns a category and urgency, suggests routing tags and a next action, and drafts a customer response. FastAPI keeps the model access key on the server, while a lightweight browser interface renders the validated result.

What this project demonstrates

  • Calling DigitalOcean's OpenAI-compatible Chat Completions endpoint.
  • Using a single function tool and JSON Schema for structured model output.
  • Validating untrusted model output before returning it to the browser.
  • Keeping model credentials out of front-end code.
  • Handling authentication, rate-limit, timeout, and malformed-response failures.
  • Running the same application locally, in Docker, and on App Platform.
  • Provisioning the App Platform application with Terraform.

Request flow

  1. The browser sends a ticket to the FastAPI backend.
  2. The backend validates length, plan, and field constraints.
  3. It sends the ticket to https://inference.do-ai.run/v1/chat/completions.
  4. The model calls submit_ticket_triage with structured arguments.
  5. Pydantic validates those arguments before the API returns them to the browser.

Serverless Inference runs the model. App Platform runs the application that consumes the model.

Prerequisites

  • Python 3.11 or later.
  • A DigitalOcean account with a positive Serverless Inference prepaid balance.
  • A model access key scoped to mimo-v2.5-pro, or another model that supports tool calling.

Model access keys are preferable to broad personal access tokens for application workloads because they can be scoped to selected models.

Run locally

Create a virtual environment and install the application:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"

Configure the runtime without committing credentials:

cp .env.example .env

Edit .env, then export its values and start the API:

set -a
source .env
set +a
uvicorn app.main:app --reload --port 8080

Open http://localhost:8080.

You can also call the API directly:

curl --request POST http://localhost:8080/api/triage \
  --header 'Content-Type: application/json' \
  --data '{
    "subject": "Production API is timing out",
    "description": "Every request takes more than 30 seconds and checkout is blocked.",
    "customer_plan": "business"
  }'

If APP_ACCESS_TOKEN is configured, add:

--header 'X-App-Access-Token: your-demo-access-code'

Run the checks

The automated suite mocks DigitalOcean Inference. It does not need credentials and does not incur inference charges.

ruff check .
ruff format --check .
pytest

Run with Docker

docker build -t do-inference-ticket-triage .
docker run --rm \
  --publish 8080:8080 \
  --env DIGITALOCEAN_INFERENCE_KEY \
  --env DIGITALOCEAN_INFERENCE_MODEL=mimo-v2.5-pro \
  do-inference-ticket-triage

Open http://localhost:8080/health to check the container without sending a billable inference request.

Deploy to App Platform with Terraform

Push this project to a GitHub repository, then follow terraform/README.md.

The deployment configuration creates an App Platform service from the repository's Dockerfile and supplies the model access key as an encrypted runtime environment variable.

Terraform state still contains the original secret value. Protect the state, and never commit it.

Configuration

Variable Required Default Purpose
DIGITALOCEAN_INFERENCE_KEY Yes Model access key used by the backend
DIGITALOCEAN_INFERENCE_MODEL No mimo-v2.5-pro Tool-capable model ID
DIGITALOCEAN_INFERENCE_BASE_URL No https://inference.do-ai.run/v1 Serverless API base URL
INFERENCE_TIMEOUT_SECONDS No 45 Upstream request timeout
APP_ACCESS_TOKEN No Shared code for a short-lived public demo

Security and operational notes

  • Never put the model access key in JavaScript, HTML, screenshots, or Git history.
  • Scope the model access key only to models the application needs.
  • Ticket text is untrusted input. The system prompt explicitly treats it as data, but prompt-injection defenses are not a substitute for authorization.
  • The optional shared access code deters casual misuse; it is not production identity or authorization.
  • Add proper authentication and per-user rate limits before operating this as a public service.
  • Do not log raw ticket descriptions unless your privacy and retention policies explicitly allow it.
  • Human review is required before sending a generated response to a customer.
  • Destroy short-lived demo resources and revoke their keys when finished.

Cost behavior

Serverless Inference is charged per input and output token and requires a positive prepaid balance. App Platform is billed separately for the running service. The API response shows token usage when the selected model reports it, making it possible to add application-level cost telemetry later.

See the current Inference pricing documentation before publishing cost examples.

Repository layout

.
├── app/
│   ├── config.py           # Environment-backed settings
│   ├── inference.py        # DigitalOcean API client and tool schema
│   ├── main.py             # FastAPI routes and safe error mapping
│   ├── models.py           # Input and model-output validation
│   └── static/             # Browser interface
├── terraform/              # App Platform deployment
├── tests/                  # Mocked API and inference-client tests
├── Dockerfile
└── pyproject.toml

Why a tool call instead of "return JSON"

Prompting a model to return JSON does not guarantee a stable shape. This demo defines submit_ticket_triage as the only function tool, instructs the model to call it exactly once, and supplies the Pydantic-generated JSON Schema as its parameters. It uses tool_choice: "auto" because DigitalOcean's MiMo adapter currently rejects the named forced-tool object. The returned arguments are then validated again, making failures explicit instead of quietly sending malformed or unexpected fields to the UI.

About

Support ticket triage demo using DigitalOcean Serverless Inference, FastAPI, App Platform, and Terraform

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages