[AZ-178] Implement streaming video detection endpoint

- Added `/detect/video` endpoint for true streaming video detection, allowing inference to start as upload bytes arrive.
- Introduced `run_detect_video_stream` method in the inference module to handle video processing from a file-like object.
- Updated media hashing to include a new function for computing hashes directly from files with minimal I/O.
- Enhanced documentation to reflect changes in video processing and API behavior.

Made-with: Cursor
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-04-01 03:11:43 +03:00
parent e65d8da6a3
commit be4cab4fcb
42 changed files with 2983 additions and 29 deletions
+82
View File
@@ -0,0 +1,82 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
REGISTRY="${REGISTRY:?REGISTRY is required}"
IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
DEPLOY_HOST="${DEPLOY_HOST:-}"
DEPLOY_USER="${DEPLOY_USER:-deploy}"
usage() {
echo "Usage: $0 [--rollback] [--help]"
echo ""
echo "Deploy Azaion.Detections to a target machine."
echo ""
echo "Options:"
echo " --rollback Redeploy the previous image tag"
echo " --help Show this help message"
echo ""
echo "Environment variables:"
echo " REGISTRY Container registry URL (required)"
echo " IMAGE_TAG Image tag to deploy (required)"
echo " DEPLOY_HOST Target machine (empty = local)"
echo " DEPLOY_USER SSH user (default: deploy)"
exit 0
}
run_cmd() {
if [ -n "$DEPLOY_HOST" ]; then
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "$@"
else
eval "$@"
fi
}
ROLLBACK=0
for arg in "$@"; do
case "$arg" in
--rollback) ROLLBACK=1 ;;
--help) usage ;;
esac
done
if [ "$ROLLBACK" -eq 1 ]; then
PREV_TAG_FILE="$PROJECT_ROOT/.deploy-previous-tag"
if [ ! -f "$PREV_TAG_FILE" ]; then
echo "ERROR: No previous tag found at $PREV_TAG_FILE"
exit 1
fi
IMAGE_TAG="$(cat "$PREV_TAG_FILE")"
echo "Rolling back to image tag: $IMAGE_TAG"
fi
echo "=== Deploying Azaion.Detections ==="
echo "Registry: $REGISTRY"
echo "Image tag: $IMAGE_TAG"
echo "Target: ${DEPLOY_HOST:-localhost}"
echo ""
echo "--- Pulling images ---"
bash "$SCRIPT_DIR/pull-images.sh"
echo "--- Stopping services ---"
bash "$SCRIPT_DIR/stop-services.sh"
echo "--- Starting services ---"
bash "$SCRIPT_DIR/start-services.sh"
echo "--- Health check ---"
if bash "$SCRIPT_DIR/health-check.sh"; then
echo "=== Deployment successful ==="
else
echo "ERROR: Health check failed. Run '$0 --rollback' to revert."
exit 1
fi
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
set -euo pipefail
HOST="${HEALTH_CHECK_HOST:-localhost}"
PORT="${HEALTH_CHECK_PORT:-8080}"
MAX_RETRIES=10
RETRY_INTERVAL=3
usage() {
echo "Usage: $0 [--help]"
echo "Check health of Azaion.Detections service."
echo ""
echo "Environment variables:"
echo " HEALTH_CHECK_HOST Target host (default: localhost)"
echo " HEALTH_CHECK_PORT Target port (default: 8080)"
exit 0
}
for arg in "$@"; do
case "$arg" in
--help) usage ;;
esac
done
URL="http://${HOST}:${PORT}/health"
echo "Checking health at $URL ..."
for i in $(seq 1 "$MAX_RETRIES"); do
if curl -sf "$URL" > /dev/null 2>&1; then
RESPONSE="$(curl -sf "$URL")"
echo "Health check passed (attempt $i/$MAX_RETRIES): $RESPONSE"
exit 0
fi
echo "Attempt $i/$MAX_RETRIES failed, retrying in ${RETRY_INTERVAL}s..."
sleep "$RETRY_INTERVAL"
done
echo "ERROR: Health check failed after $MAX_RETRIES attempts."
exit 1
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
REGISTRY="${REGISTRY:?REGISTRY is required}"
IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
usage() {
echo "Usage: $0 [--help]"
echo "Pull Docker images for Azaion.Detections from the registry."
exit 0
}
for arg in "$@"; do
case "$arg" in
--help) usage ;;
esac
done
IMAGE="${REGISTRY}/azaion/detections-cpu:${IMAGE_TAG}"
echo "Pulling $IMAGE ..."
docker pull "$IMAGE"
echo "Verifying image digest..."
docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || echo "Warning: digest not available for local images"
echo "Pull complete."
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
REGISTRY="${REGISTRY:?REGISTRY is required}"
IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
LOADER_URL="${LOADER_URL:-http://loader:8080}"
ANNOTATIONS_URL="${ANNOTATIONS_URL:-http://annotations:8080}"
usage() {
echo "Usage: $0 [--help]"
echo "Start Azaion.Detections service container."
exit 0
}
for arg in "$@"; do
case "$arg" in
--help) usage ;;
esac
done
IMAGE="${REGISTRY}/azaion/detections-cpu:${IMAGE_TAG}"
CONTAINER_NAME="azaion-detections"
echo "Starting $CONTAINER_NAME from $IMAGE ..."
docker run -d \
--name "$CONTAINER_NAME" \
--restart unless-stopped \
-p 8080:8080 \
-e LOADER_URL="$LOADER_URL" \
-e ANNOTATIONS_URL="$ANNOTATIONS_URL" \
-v "$(pwd)/classes.json:/app/classes.json:ro" \
--shm-size=512m \
--memory=4g \
"$IMAGE"
echo "Container $CONTAINER_NAME started."
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
CONTAINER_NAME="azaion-detections"
GRACE_PERIOD=30
usage() {
echo "Usage: $0 [--help]"
echo "Gracefully stop Azaion.Detections service container."
exit 0
}
for arg in "$@"; do
case "$arg" in
--help) usage ;;
esac
done
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
CURRENT_IMAGE="$(docker inspect --format='{{.Config.Image}}' "$CONTAINER_NAME" 2>/dev/null || true)"
if [ -n "$CURRENT_IMAGE" ]; then
CURRENT_TAG="${CURRENT_IMAGE##*:}"
echo "$CURRENT_TAG" > "$PROJECT_ROOT/.deploy-previous-tag"
echo "Saved previous tag: $CURRENT_TAG"
fi
echo "Stopping $CONTAINER_NAME (${GRACE_PERIOD}s grace period)..."
docker stop -t "$GRACE_PERIOD" "$CONTAINER_NAME" || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
echo "Stopped and removed $CONTAINER_NAME."
else
echo "Container $CONTAINER_NAME is not running."
fi
docker container prune -f --filter "label=com.docker.compose.project=azaion-detections" 2>/dev/null || true