Skip to main content

Architecture Handlers

A minimal, extensible Python library providing a base class (ArchitectureHandler) for building handler components that accept inputs, optionally perform network requests, and publish results via thread-safe queues. Ships with concrete handlers for AI/agent tasks: speech-to-text, text-to-speech, face recognition, gesture generation, LLM agent interaction, and Ollama chat.

Package: scs-architecture-handlers · Python: >= 3.10 · License: MIT


Table of Contents


Features

  • Threaded processing loop — consumes items from an input queue, processes them, and writes results to a result queue.
  • Pluggable core logic — override generate_results() or supply generate_results_callback in config.
  • Template methods — validate_item, preprocess_item, postprocess_result for easy adaptation.
  • Optional type checking — expected_type catches mismatched inputs at the boundary.
  • Dropping policy — bounded queues with configurable capacity; drops are counted and logged.
  • Runtime instrumentation — timestamps and counters (processed/dropped/errors/network errors) via stats().
  • Async wrappers — all sync methods have async_* counterparts (powered by asyncio.to_thread).
  • Hook methods — 9 instrumentation hooks (_hook_before_feed, _hook_after_generate, etc.) for monitoring.
  • Non-blocking callbacks — dedicated callback worker thread so user callbacks never stall the hot path.
  • Singleton sync core — async wrappers delegate to the same sync implementation; no code duplication.

Installation

From PyPI

pip install scs-architecture-handlers
from scs_architecture_handlers.base_handler import ArchitectureHandler

Development setup

# Clone the repository
git clone <repo-url>
cd architecture-handlers

# Create a virtual environment (Python >= 3.10)
python3.11 -m venv .venv
source .venv/bin/activate

# Install dependencies (using pip)
pip install -r requirements.txt

# Or using uv
uv sync

Handlers Overview

Handler File Purpose
ArchitectureHandler base_handler.py Extensible base class for all handlers.
FaceRecognitionHandler face_recognition_handler.py Posts camera frames to a /detect FastAPI endpoint. Optional webcam auto-capture mode.
GestureGenerationHandler gesture_generation_handler.py Sends audio chunks to a /generate gesture FastAPI for realtime beat-driven gesture synthesis.
LLMAgentHandler llm_agent_handler.py Sends text or person data to an LLM agent FastAPI service.
STTHandler stt_handler.py Speech-to-text via RealtimeSTT.AudioToTextRecorderClient (WebSocket).
RealtimeSTTHandler (v2) stt_handler_v2.py Speech-to-text via WebRTC / aiortc with _AudioTrackProxy and _MicrophoneCapturer.
F5TTSHandler f5tts_handler.py Text-to-speech via an F5-TTS FastAPI /synthesize endpoint.
MaverickAgentHandler maverick_agent_handler.py Orchestrator: TTS + gesture generation + Unity visualizer streaming via WebSocket.
OllamaChatAgent ollama_handler.py Stateful chat wrapper around ollama.Client with conversation history, save/load, and error types.

Design Decisions

  1. Single sync core, async wrappers on top. All async methods delegate to the sync implementation via asyncio.to_thread. This means there is exactly one implementation of the processing logic — no duplicated sync/async code paths.

  2. Template Method pattern. The base class defines the skeleton of the feed → validate → preprocess → generate → postprocess → publish pipeline. Subclasses override only the steps they need (validate_item, preprocess_item, generate_results, postprocess_result).

  3. Bounded queues with backpressure. Both input and result queues have configurable max sizes. When a queue is full, items are silently dropped and dropped_count is incremented. This prevents unbounded memory growth under load.

  4. Dedicated async callback thread. External callbacks (e.g., database writes, network calls) can be scheduled via _emit_async_callback to run on a separate worker thread, keeping the main processing path fast and predictable.

  5. Hook-based instrumentation. All major lifecycle events fire hook methods. Subclasses and monitoring tools can override these hooks without modifying the core pipeline.

  6. Dry-run mode in all network handlers. Every handler that performs network I/O supports a dry_run flag that returns stub results without making HTTP calls. This makes testing and offline development straightforward.

  7. Weak reference finalizer. A weakref.finalize ensures background threads are joined when the handler is garbage-collected, preventing orphaned threads.


Usage

1) Direct synchronous generation

Subclass ArchitectureHandler and override generate_results:

from scs_architecture_handlers.base_handler import ArchitectureHandler


class EchoHandler(ArchitectureHandler):
    def generate_results(self, item, extra):
        return {"echo": item, "meta": extra}


h = EchoHandler(run_as_thread=False)
out = h.generate("hello", tag=1)
print(out)  # {"echo": "hello", "meta": {"tag": 1}}

h.cleanup()

2) Threaded pipeline

Use the internal worker thread to consume items from the input queue and push processed results to the result queue:

import time
from scs_architecture_handlers.base_handler import ArchitectureHandler


class Doubler(ArchitectureHandler):
    def generate_results(self, item, extra):
        return item * 2


h = Doubler(run_as_thread=True, disable_thread=False)
h.feed(10)
print(h.get_result(timeout=1.0))  # 20
h.cleanup()

3) Async wrappers

All public sync methods have async counterparts:

import asyncio
from scs_architecture_handlers.base_handler import ArchitectureHandler


class EchoHandler(ArchitectureHandler):
    def generate_results(self, item, extra):
        return {"echo": item}


async def main():
    h = EchoHandler(run_as_thread=False)
    out = await h.async_generate("async-hello")
    print(out)  # {"echo": "async-hello"}
    await h.async_cleanup()


asyncio.run(main())

Available async wrappers: async_feed, async_get_result, async_generate, async_start, async_cleanup.

4) Callbacks & non-blocking execution

Schedule external callbacks on a dedicated thread via _emit_async_callback:

import time
from scs_architecture_handlers.base_handler import ArchitectureHandler


def on_result(item, extra):
    time.sleep(0.1)
    print("callback got:", item)


class NonBlockingHandler(ArchitectureHandler):
    def generate_results(self, item, extra):
        result = {"value": str(item).upper(), "extra": extra}
        self._emit_async_callback(result, extra)
        return result


h = NonBlockingHandler(
    run_as_thread=False,
    disable_thread=False,
    generate_results_callback=on_result,
    callback_queue_size=8,
)

for i in range(5):
    out = h.generate(f"msg-{i}")
    assert out["value"] == f"MSG-{i}"

time.sleep(0.5)
h.cleanup()

Notes:

  • If the callback queue fills, new tasks are dropped and dropped_count increments.
  • For producer-style handlers (e.g., microphone/STT), use _emit_async_callback inside the production path.

Extension Points

Override these template methods to adapt the handler:

Method Purpose
validate_item(item, extra) -> bool Return False to drop invalid items early (shape/content/type).
preprocess_item(item, extra) -> (item, extra) Normalize or transform raw input before generate_results.
generate_results(item, extra) -> Any Core computation (required — must override or supply callback).
postprocess_result(item, extra, result) -> Any Final transformation (e.g., map indices to labels).
_prepare_request_payload(item, extra) -> dict Build structured payload for network I/O.
_perform_request(payload) -> Any Implement actual network request (override this, call via perform_request).

Instrumentation hooks (optional overrides):

Hook When it fires
_hook_before_feed / _hook_after_feed Before/after feed()
_hook_before_generate / _hook_after_generate Before/after generate_results()
_hook_before_network_call / _hook_after_network_call Before/after a network request
_hook_after_result When a result is retrieved via get_result()
_hook_on_error When generation raises an exception
_hook_network_error When a network call fails

Configuration Reference

Key Default Description
host None Remote host (optional).
port None Remote port (optional).
auth None Authentication token/credentials (optional).
run_as_thread True Start internal worker threads.
disable_thread False Force-disable threading even if run_as_thread is True.
max_queue_size 128 Capacity for the input queue.
result_queue_size max_queue_size Capacity for the result queue.
verbose False Enable INFO-level logging (default is WARNING).
expected_type None Type or tuple for basic validation in validate_item.
generate_results_callback None External callback alternative to subclassing generate_results.
network_timeout None Optional timeout for network requests.
client_id_prefix "client" Prefix for auto-generated client ID.
callback_queue_size 128 Capacity for the async callback queue (used with _emit_async_callback).

Stats & Monitoring

stats = handler.stats()
print(stats)
# {
#   "client_id": "client-...",
#   "created_at": ...,
#   "last_feed_at": ...,
#   "last_generate_at": ...,
#   "last_result_at": ...,
#   "last_network_call_at": ...,
#   "input_queue_size": 0,
#   "result_queue_size": 0,
#   "run_as_thread": True,
#   "processed_count": 42,
#   "dropped_count": 0,
#   "error_count": 0,
#   "network_error_count": 0,
# }

All counters are updated automatically by the default hook implementations. Override hooks for custom monitoring.


Development

Setup

python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Running Tests

Tests use pytest with pytest-asyncio and pytest-timeout. They mock external services so no live servers are needed.

pytest -q
# or
pytest tests/

Individual test files:

Test File Tests For
tests/test_base_handler.py Core ArchitectureHandler (init, feed, generate, threading, hooks, callbacks, cleanup, stats)
tests/test_f5tts_handler.py F5TTSHandler
tests/test_face_recognition_handler.py FaceRecognitionHandler
tests/test_gesture_generation_handler.py GestureGenerationHandler
tests/test_llm_agent_handler.py LLMAgentHandler
tests/test_maverick_agent_handler.py MaverickAgentHandler
tests/test_stt_handler.py STTHandler (v1 / RealtimeSTT)
tests/test_realtime_stt_handler.py STTHandler (v2 / WebRTC)

System Dependencies

On Debian/Ubuntu, you may need:

sudo apt-get update
sudo apt-get install -y portaudio19-dev

CI/CD & Releasing to PyPI

The project uses GitLab CI (.gitlab-ci.yml) with four stages:

  1. test — runs pytest -q on all branches and merge requests.
  2. secret-detection — GitLab Secret Detection template.
  3. build — builds sdist+wheel on version tags.
  4. deploy — publishes to PyPI via Twine on version tags.

To release a new version:

# 1. Update version in pyproject.toml
# 2. Commit and tag
git tag v0.2.6
git push origin v0.2.6

The deploy job verifies the tag matches pyproject.toml version automatically.

Prerequisites:

  • Set a protected, masked CI variable PYPI_TOKEN with your PyPI API token in GitLab → Settings → CI/CD → Variables.
  • Optionally override PYPI_REPOSITORY_URL to point at TestPyPI for testing.

License

MIT

Metadata

Release files for scs-architecture-handlers 0.2.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scs-architecture-handlers 0.2.7
File Size Uploaded
scs_architecture_handlers-0.2.7.tar.gz 59.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for scs-architecture-handlers 0.2.7
File Interpreter ABI Platform
scs_architecture_handlers-0.2.7-py3-none-any.whl Python 3 none any Details

Total release size: 112.9 kB

Release files / scs_architecture_handlers-0.2.7.tar.gz

Download URL scs_architecture_handlers-0.2.7.tar.gz
Size 59.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c8b4244cb11bea66d3ebd8594b615c3dc77cd4c5c5dbfa26421bd3231fefdd46
BLAKE2b-256 checksum
How to use checksums
583621d492ddca71b05b7188e51fdcc8fdd81f5c610a7fd3f2095c011df6ee18
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / scs_architecture_handlers-0.2.7-py3-none-any.whl

Download URL scs_architecture_handlers-0.2.7-py3-none-any.whl
Size 53.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c781d7ea0dde2817b5024d4abc647f7bc7f9615bd9458abe0721f2284ef3f254
BLAKE2b-256 checksum
How to use checksums
6409639dc86e3378b3f91a4fd59a55f711d79ba1abc73a3521639c823ec0cc17
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release history Release notifications | RSS feed

0.2.9

2 release files

0.2.8

2 release files

This release

0.2.7 This release

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page