classify

package
v2.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package classify defines task-oriented inference interfaces for non-LLM workloads. The primary surface is classifier interfaces — audio / text / image / video — that each take input bytes and return []LabelScore (categorical, ranked by confidence). Backends (HuggingFace Inference API, ONNX, Replicate, …) implement one or more of these; eval handlers depend on the task interface, never on the backend.

Parallel to runtime/tts and runtime/stt: each is a task interface with multiple backends behind it. runtime/providers handles chat completion (Predict); classify covers classification.

Embedder lives here for convenience — the HuggingFace Inference API exposes embedding (feature-extraction) models through the same endpoint family as classification models, so the HF backend satisfies Embedder as a side effect. It is NOT the canonical home for embedding providers. OpenAI, VoyageAI, and similar dedicated embedding APIs continue to register under `role: embedding` via the runtime/providers Embed() interface; cosine-similarity-style handlers depend on that path. Future embedder backends that happen to live in runtime/classify (e.g. an HF-hosted embedding model) are bridged into the same handler path via adapters, not by relocating providers. Treat Embedder here as a convenience surface, not a migration target.

TopicClassifier is the exception to the bytes-in/[]LabelScore-out shape: it takes a structured TopicRequest (a policy plus the message under judgment) and returns a TopicDecision, because a topic-scope verdict is not a ranked label set.

Index

Constants

View Source
const (
	SmallTalkAllow = "allow"
	SmallTalkDeny  = "deny"
)

Small-talk dispositions. A policy says whether greetings, thanks and pleasantries — which match no listed subject — count as in scope.

Variables

This section is empty.

Functions

func RegisterBackend

func RegisterBackend(reg *Registry, id string, b Backend) []string

RegisterBackend registers b under id against every task interface it implements, returning the task labels registered (e.g. ["audio", "text"]). A backend that satisfies no task interface registers nothing and returns an empty slice. Shared by BuildRegistry and the SDK's programmatic options so the type-assert logic lives in one place.

It does not touch defaults. Callers that register incrementally — one provider per SDK option, with nothing running afterwards to assign defaults — want RegisterBackendDefaulting instead.

func RegisterBackendDefaulting added in v2.2.0

func RegisterBackendDefaulting(reg *Registry, id string, b Backend) []string

RegisterBackendDefaulting registers b exactly as RegisterBackend does and, for every task interface it implements, claims that task's default when no default is set yet. Returns the task labels registered.

Use it wherever backends arrive one at a time and nothing runs afterwards to assign defaults — the SDK's WithInferenceProvider / WithClassifier options and the `role: inference` config path. Without it a backend registers successfully and then every handler lookup that doesn't name an explicit id fails with "no default classifier".

BuildRegistry deliberately keeps RegisterBackend plus its own applyDefaults pass: it sees the whole spec list up front, so it can honor an explicit RegistryDefaults entry over the first-declared one. The two paths agree on first-wins whenever no explicit default is given.

func RegisterFactory

func RegisterFactory(providerType string, f Factory)

RegisterFactory registers a factory for the given provider type. Typically called from a per-backend package init().

func RegisteredTypes

func RegisteredTypes() []string

RegisteredTypes returns the inference provider types with a registered factory, sorted. Use it to check a configured type before CreateFromSpec rather than constructing and parsing the error.

func ResolveCredential

func ResolveCredential(
	ctx context.Context,
	providerType string,
	cfgDir string,
	cred *credentials.CredentialConfig,
) (credentials.Credential, error)

ResolveCredential is a thin wrapper around base.ResolveCredential, matching tts.ResolveCredential / stt.ResolveCredential.

func WithRegistry

func WithRegistry(ctx context.Context, r *Registry) context.Context

WithRegistry returns ctx with the Registry attached. Arena's eval orchestrator calls this once per run; handlers retrieve via FromContext.

Types

type AudioChunk

type AudioChunk struct {
	// PCM is the raw PCM audio bytes for this chunk. Format
	// declared by the parent AudioStreamOptions.
	PCM []byte
	// Final marks the last chunk; backends may flush state.
	Final bool
}

AudioChunk is a single packet in a streaming audio classification request. Backends that stream consume these from a channel until it closes.

type AudioClassifier

type AudioClassifier interface {
	ClassifyAudio(ctx context.Context, audio []byte, opts AudioOptions) ([]LabelScore, error)
}

AudioClassifier classifies a single audio clip into one or more labeled scores. Required interface for every backend that supports audio (HF base, Hume, Deepgram, ONNX).

Implementations must be safe for concurrent use; the registry hands the same instance to multiple eval handlers.

type AudioOptions

type AudioOptions struct {
	// Model is the backend-specific model identifier (e.g.
	// "superb/wav2vec2-base-superb-er" on HuggingFace).
	Model string

	// Language is an optional ISO-639-1 hint (e.g. "en"). Only used
	// by backends that route by language.
	Language string

	// SampleRate is the source audio sample rate in Hz. Backends
	// that can resample internally use this to drive it. The
	// shipped HuggingFace backend does NOT resample — handlers
	// are expected to deliver audio at the rate the target model
	// wants (typically 16 kHz mono for SER models). The field is
	// kept on the options struct so future backends (ONNX, Hume,
	// etc.) that do resample have a place to read the source rate
	// from without growing a per-backend option type.
	SampleRate int

	// MIMEType is the audio container / codec hint (e.g. "audio/wav",
	// "audio/L16"). Backends that need explicit format selection use
	// this; others ignore.
	MIMEType string
}

AudioOptions carries per-call knobs for audio classification. Backends ignore fields they don't support; consumers set what matters for their target model.

type AudioStreamOptions

type AudioStreamOptions struct {
	AudioOptions
	// ChunkInterval is the source's emit cadence; backends use it
	// to size analysis windows and stamp output timestamps.
	ChunkInterval time.Duration
}

AudioStreamOptions carries the framing contract for a streaming audio classification request.

type Backend

type Backend = any

Backend is whatever a factory returns: a value that implements one or more of the task interfaces (AudioClassifier, TextClassifier, …). RegisterBackend type-asserts it against each. It is intentionally an alias for any — there is no method common to all task interfaces.

func CreateFromSpec

func CreateFromSpec(spec ProviderSpec) (Backend, error)

CreateFromSpec builds a Backend for the spec's Type.

type EmbedOptions

type EmbedOptions struct {
	// Model is the backend-specific model identifier (e.g.
	// "voyage-3", "text-embedding-3-large").
	Model string

	// Dimensions optionally requests truncation to a specific
	// dimensionality. Backend ignores if not supported.
	Dimensions int

	// InputType disambiguates query vs document embedding for
	// asymmetric models (e.g. Voyage's `query` / `document`).
	// Empty = backend default.
	InputType string
}

EmbedOptions carries per-call knobs for text embedding.

type Embedder

type Embedder interface {
	Embed(ctx context.Context, inputs []string, opts EmbedOptions) ([][]float32, error)
}

Embedder turns text inputs into dense vectors. Co-located with the classifiers because it shares the same shape (task interface + multiple backends + registry lookup) and because moving embeddings here breaks the historical dependency between runtime/evals/handlers/cosine_similarity.go and concrete provider packages.

The current cosine_similarity handler reads pre-computed embeddings from EvalContext.Metadata — it doesn't call an Embedder directly. Migrating to this interface is queued (see phase 2 of the inference abstraction proposal); the interface lives here from day one so the migration doesn't introduce a new package later.

type Factory

type Factory = base.Factory[Backend]

Factory builds a Backend from a spec. Per-backend packages register one via init() (see runtime/classify/backends/hf/register.go) so this package never imports them.

type ImageClassifier

type ImageClassifier interface {
	ClassifyImage(ctx context.Context, img []byte, opts ImageOptions) ([]LabelScore, error)
}

ImageClassifier classifies a single still image. Visual content moderation (NSFW, violence, brand safety), scene tagging, object recognition all go through this. No streaming sibling — a still image is a single inference.

type ImageOptions

type ImageOptions struct {
	// Model is the backend-specific model identifier (e.g.
	// "Falconsai/nsfw_image_detection" on HuggingFace).
	Model string

	// MIMEType is the image format hint (e.g. "image/png", "image/jpeg").
	MIMEType string
}

ImageOptions carries per-call knobs for image classification.

type LabelScore

type LabelScore struct {
	Label string
	Score float64
}

LabelScore pairs a classifier label with a confidence score in [0, 1]. Backends return slices of these sorted by descending score where the model supports ranking; the caller treats the order as hint only and looks up by Label when checking expected values.

type LabelScoreEvent

type LabelScoreEvent struct {
	Timestamp time.Duration
	Window    time.Duration
	Scores    []LabelScore
}

LabelScoreEvent is one window's worth of classification output from a streaming backend. Timestamp is relative to the start of the input stream.

type ProviderSpec

type ProviderSpec = base.CapabilitySpec

ProviderSpec is the runtime form of an inference-provider declaration. Aliased to base.CapabilitySpec so the field shape is shared with the TTS, STT, embedding, and image factories (id/type/model/base_url/ credential/additional_config).

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds named classifier and embedder instances keyed by an id supplied at config time (e.g. "hf", "hf-azure", "onnx-local"). Eval handlers look up by id; the id-to-backend mapping is the only thing the handler config needs to know about.

Backends register themselves into a Registry at engine startup; the registry then travels with context.Context to handlers via WithRegistry / FromContext.

func BuildRegistry

func BuildRegistry(specs []ProviderSpec, defaults RegistryDefaults) (*Registry, error)

BuildRegistry constructs a Registry from specs, registering each backend against every task interface it implements, then applies defaults. For any task with no explicit default, the first-declared provider implementing it becomes the default (first-wins, matching STT/TTS service defaults). Returns (nil, nil) when specs is empty — classification is optional; callers that don't use it must not require a token.

func FromContext

func FromContext(ctx context.Context) *Registry

FromContext returns the Registry attached to ctx, or nil if none. Eval handlers that don't find a registry fall back to a "skipped" result rather than failing — classification is an optional feature of the runtime, not a hard dependency.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry. Backends are added via RegisterAudio / RegisterText / etc.; defaults are set with the SetDefault* methods.

func (*Registry) AudioClassifier

func (r *Registry) AudioClassifier(id string) (AudioClassifier, error)

AudioClassifier resolves by id, falling back to the configured default when id is empty. Returns a non-nil error when nothing matches.

func (*Registry) Embedder

func (r *Registry) Embedder(id string) (Embedder, error)

Embedder resolves by id with default fallback.

func (*Registry) ImageClassifier

func (r *Registry) ImageClassifier(id string) (ImageClassifier, error)

ImageClassifier resolves by id with default fallback.

func (*Registry) RegisterAudio

func (r *Registry) RegisterAudio(id string, c AudioClassifier)

RegisterAudio adds an AudioClassifier under the given id. Calling twice with the same id replaces the previous instance.

func (*Registry) RegisterEmbedder

func (r *Registry) RegisterEmbedder(id string, e Embedder)

RegisterEmbedder adds an Embedder.

func (*Registry) RegisterImage

func (r *Registry) RegisterImage(id string, c ImageClassifier)

RegisterImage adds an ImageClassifier.

func (*Registry) RegisterText

func (r *Registry) RegisterText(id string, c TextClassifier)

RegisterText adds a TextClassifier.

func (*Registry) RegisterTopic added in v2.2.0

func (r *Registry) RegisterTopic(id string, c TopicClassifier)

RegisterTopic adds a TopicClassifier.

func (*Registry) RegisterVideo

func (r *Registry) RegisterVideo(id string, c VideoClassifier)

RegisterVideo adds a VideoClassifier.

func (*Registry) SetDefaultAudio

func (r *Registry) SetDefaultAudio(id string) error

SetDefaultAudio names the AudioClassifier used when a handler doesn't pass an explicit id. The id must already be registered.

func (*Registry) SetDefaultEmbedder

func (r *Registry) SetDefaultEmbedder(id string) error

SetDefaultEmbedder names the default Embedder.

func (*Registry) SetDefaultImage

func (r *Registry) SetDefaultImage(id string) error

SetDefaultImage names the default ImageClassifier.

func (*Registry) SetDefaultText

func (r *Registry) SetDefaultText(id string) error

SetDefaultText names the default TextClassifier.

func (*Registry) SetDefaultTopic added in v2.2.0

func (r *Registry) SetDefaultTopic(id string) error

SetDefaultTopic names the default TopicClassifier.

func (*Registry) SetDefaultVideo

func (r *Registry) SetDefaultVideo(id string) error

SetDefaultVideo names the default VideoClassifier.

func (*Registry) TextClassifier

func (r *Registry) TextClassifier(id string) (TextClassifier, error)

TextClassifier resolves by id with default fallback.

func (*Registry) TopicClassifier added in v2.2.0

func (r *Registry) TopicClassifier(id string) (TopicClassifier, error)

TopicClassifier resolves by id with default fallback.

func (*Registry) VideoClassifier

func (r *Registry) VideoClassifier(id string) (VideoClassifier, error)

VideoClassifier resolves by id with default fallback.

type RegistryDefaults

type RegistryDefaults struct {
	AudioClassifier string
	TextClassifier  string
	ImageClassifier string
	VideoClassifier string
	Embedder        string
	TopicClassifier string
}

RegistryDefaults pins which provider id serves each task when a handler doesn't name one. Mirrors config.InferenceDefaults but lives in runtime so both Arena and the SDK map onto it.

type StreamingAudioClassifier

type StreamingAudioClassifier interface {
	AudioClassifier
	ClassifyAudioStream(
		ctx context.Context,
		chunks <-chan AudioChunk,
		opts AudioStreamOptions,
	) (<-chan LabelScoreEvent, error)
}

StreamingAudioClassifier is the optional capability for live classification — Hume, Deepgram, and locally-windowed ONNX implement it; HF Inference API base does not. Eval handlers that only need end-of-turn classification depend on AudioClassifier; hooks and guardrails that react mid-call type-assert to this.

type StreamingVideoClassifier

type StreamingVideoClassifier interface {
	VideoClassifier
	ClassifyVideoStream(
		ctx context.Context,

		chunks <-chan struct{},
		opts VideoOptions,
	) (<-chan LabelScoreEvent, error)
}

StreamingVideoClassifier is the optional capability for live video classification (mostly a future concern — agentic-UI replay, security camera streams). No MVP backend implements it; the interface stays in the package so the synchronous one doesn't break when a streaming consumer arrives.

type TextClassifier

type TextClassifier interface {
	ClassifyText(ctx context.Context, text string, opts TextOptions) ([]LabelScore, error)
}

TextClassifier classifies a single text string. Toxicity, sentiment, emotion-from-text, intent, language detection — anything that takes text in and returns labeled scores.

Text inputs aren't temporally extended, so there's no streaming sibling. Batch text classification (many strings at once) goes through repeated calls — backends that support batching internally can pool requests.

type TextOptions

type TextOptions struct {
	// Model is the backend-specific model identifier (e.g.
	// "unitary/toxic-bert" on HuggingFace).
	Model string

	// Language is an optional ISO-639-1 hint.
	Language string

	// MultiLabel asks the backend to return scores for every label
	// rather than a single best one. Useful for toxicity panels
	// (toxic, severe_toxic, obscene, …) where multiple may apply.
	MultiLabel bool
}

TextOptions carries per-call knobs for text classification.

type TopicClassifier added in v2.2.0

type TopicClassifier interface {
	ClassifyTopic(ctx context.Context, req TopicRequest) (TopicResult, error)
}

TopicClassifier decides whether a user message falls inside a declared conversational scope. The sixth task interface in this package; see the package doc for how backends bind to tasks.

type TopicDecision added in v2.2.0

type TopicDecision string

TopicDecision is a classifier's verdict about one user message.

const (
	// TopicAllow means the message falls inside the declared scope.
	TopicAllow TopicDecision = "allow"
	// TopicDeny means the message falls outside it.
	TopicDeny TopicDecision = "deny"
	// TopicUnknown means the backend could not decide: an unreachable
	// service, or a response that did not parse. Callers map it to a
	// policy-configured outcome rather than guessing.
	TopicUnknown TopicDecision = "unknown"
)

type TopicExamples added in v2.2.0

type TopicExamples struct {
	Allowed    []string
	Disallowed []string
}

TopicExamples is an optional labeled corpus. It is a classification aid, not configuration: backends may fold it into a prompt or ignore it.

type TopicPolicy added in v2.2.0

type TopicPolicy struct {
	// Description is the application's purpose in prose. Required — an
	// allow-list alone reads as keywords to a semantic classifier.
	Description string
	// Allowed lists in-scope subjects. Required and non-empty: policy is
	// default-deny, so an empty list would block everything.
	Allowed []string
	// Disallowed lists explicit exclusions. Optional.
	Disallowed []string
	// SmallTalk is SmallTalkAllow or SmallTalkDeny.
	SmallTalk string
	// Examples is an optional labeled corpus.
	Examples TopicExamples
}

TopicPolicy is a declared conversational scope, in the pack author's own words. It is deliberately structured rather than a free-text criteria string: a chat-shaped backend renders it into a prompt, while a future embedding or ONNX backend can consume the same fields directly, and neither requires the pack to change.

type TopicRequest added in v2.2.0

type TopicRequest struct {
	Policy  TopicPolicy
	History []TopicTurn
	// Message is the user message under judgment. Prior in-scope history
	// must not implicitly authorize it.
	Message string
}

TopicRequest is one classification: judge Message against Policy, using History only to resolve references.

type TopicResult added in v2.2.0

type TopicResult struct {
	Decision TopicDecision
	// Confidence is populated only by a backend that genuinely has one.
	// A label-emitting model does not, and must leave it nil rather than
	// manufacture a number callers might threshold on.
	Confidence *float64
	// Reason is the backend's explanation where it supplies one.
	Reason string
	// Raw is the backend's unparsed answer, for diagnostics.
	Raw string
}

TopicResult is a classifier's answer.

type TopicTurn added in v2.2.0

type TopicTurn struct {
	Role string // "user" or "assistant"
	Text string
}

TopicTurn is one prior conversation turn flattened to role and plain text.

Deliberately not types.Message: assistant text lives on Content while user text can live in Parts, and the extraction helper belongs with the eval handlers. Flattening at the caller keeps this package free of a types dependency and stops every backend re-implementing the same extraction.

type VideoClassifier

type VideoClassifier interface {
	ClassifyVideo(ctx context.Context, video []byte, opts VideoOptions) ([]LabelScore, error)
}

VideoClassifier classifies a video clip. Two physical shapes:

  • Whole-clip backends (e.g. HuggingFace Video Classification API) accept the full clip and return labels for it.
  • Decomposing backends extract the audio track and frame-sample stills, route those through AudioClassifier + ImageClassifier, and aggregate the per-modality scores. The interface is the same; backends choose the implementation.

VideoOptions.FrameSampleRate and .ExtractAudio steer decomposing backends; whole-clip backends ignore them.

type VideoOptions

type VideoOptions struct {
	// Model is the backend-specific model identifier.
	Model string

	// MIMEType is the video container hint (e.g. "video/mp4").
	MIMEType string

	// FrameSampleRate is the per-second frame extraction rate used
	// by decomposing backends (audio + sampled image classifier).
	// Whole-clip backends ignore this. 0 = backend default.
	FrameSampleRate float64

	// ExtractAudio toggles whether decomposing backends route the
	// audio track through their AudioClassifier as well as their
	// ImageClassifier. Default false.
	ExtractAudio bool
}

VideoOptions carries per-call knobs for video classification.

Directories

Path Synopsis
backends
all
Package all blank-imports every classify backend so their factories self-register.
Package all blank-imports every classify backend so their factories self-register.
hf
Package hf implements the runtime/classify interfaces against the HuggingFace Inference API.
Package hf implements the runtime/classify interfaces against the HuggingFace Inference API.
topiccontrol
Package topiccontrol implements classify.TopicClassifier against NVIDIA's Llama-3.1-NemoGuard-8B TopicControl model, served by NIM over an OpenAI-compatible chat-completions endpoint.
Package topiccontrol implements classify.TopicClassifier against NVIDIA's Llama-3.1-NemoGuard-8B TopicControl model, served by NIM over an OpenAI-compatible chat-completions endpoint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL