From 0f2f7c6915c9f213571be326409924da7cc3f84b Mon Sep 17 00:00:00 2001 From: CaioWing Date: Mon, 15 Jun 2026 18:59:33 -0300 Subject: [PATCH 1/3] feat: add release process documentation and changelog --- CHANGELOG.md | 11 ++ README.md | 25 ++++ proto/sample_envelope.proto | 236 ++++++++++++++++++++++++++++++++++++ scripts/prepare-release.ps1 | 184 ++++++++++++++++++++++++++++ 4 files changed, 456 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 proto/sample_envelope.proto create mode 100644 scripts/prepare-release.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..73d9066 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to VisionPack are tracked here. + +## [Unreleased] + +- Nothing yet. + +## [0.1.0] - 2026-06-04 + +- Initial PyPI-ready package metadata, CLI entry points, build workflow, and release publishing workflow. diff --git a/README.md b/README.md index 563f59e..286eba6 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,31 @@ Full command reference and per-command options live in the --- +## Release process + +Releases are prepared locally, reviewed as a GitHub Release draft, and published +to PyPI only when the GitHub Release is published. + +```powershell +.\scripts\prepare-release.ps1 0.1.1 +git push origin HEAD +git push origin v0.1.1 +gh release create v0.1.1 --draft --title "v0.1.1" --notes-file CHANGELOG.md +``` + +Review the draft release notes in GitHub. Publishing the release triggers +`.github/workflows/publish.yml`, which builds the package, validates the +artifacts with `twine check`, and publishes to PyPI through Trusted Publishing. + +Use `-NoCommit -NoTag` to update files and run the checks without creating the +release commit or tag: + +```powershell +.\scripts\prepare-release.ps1 0.1.1 -NoCommit -NoTag +``` + +--- + ## How it works VisionPack is **manifest-driven** and **content-addressed**: `visionpack.yaml` diff --git a/proto/sample_envelope.proto b/proto/sample_envelope.proto new file mode 100644 index 0000000..9e432a7 --- /dev/null +++ b/proto/sample_envelope.proto @@ -0,0 +1,236 @@ +syntax = "proto3"; + +package visionpack.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/CaioWing/visionpack/gen/go/visionpack/v1;visionpackv1"; + +// ============================================================================= +// SampleEnvelope — o ÚNICO contrato da plataforma (o "narrow waist"). +// +// Todo source adapter, seja qual for o runtime (DeepStream, ONNX Runtime, +// Triton, ROS2) ou transporte (MQTT, gRPC, UDS, arquivo), emite esta mensagem +// e NADA além dela. O core nunca enxerga especificidades de plataforma. +// +// Disciplina de versionamento (ver SPEC.md): +// - Dentro de v1: só mudanças ADITIVAS. Nunca renumere nem reutilize um +// número de campo. +// - Campo removido vai para `reserved` (número E nome). +// - Mudança que quebra compatibilidade bumpa o pacote: visionpack.v2. +// - proto3 preserva campos desconhecidos => forward-compat: um core antigo +// ingere envelopes de um adapter mais novo ignorando o que não conhece. +// ============================================================================= +message SampleEnvelope { + // Versão do schema, ex. "1.3". Redundante com a versão do pacote, mas útil + // para debug, filtro de logs e gating de capability em runtime. + string schema_version = 1; + + // Id único e estável desta amostra. UUIDv7 recomendado (ordenável por tempo). + string envelope_id = 2; + + // Quando o frame foi CAPTURADO no dispositivo (não quando foi enviado). + google.protobuf.Timestamp captured_at = 3; + + // De onde veio. + Source source = 4; + + // Qual modelo produziu as predições abaixo. + ModelRef model = 5; + + // Referências content-addressed para os pixels. Os bytes NÃO vão embutidos + // aqui — são enviados de forma preguiçosa (lazy) e endereçados por sha256. + // É isso que mantém o envelope minúsculo e deixa a nuvem decidir o que + // hidratar de verdade. + BlobRef frame = 6; + BlobRef thumbnail = 7; // opcional, preview barato para triagem + repeated BlobRef crops = 8; // opcional, recortes por objeto + + // Predições task-agnósticas. Uma amostra pode carregar várias (ex. um objeto + // por anotação). + repeated Annotation predictions = 9; + + // Embedding opcional para scoring de drift / novidade. + Embedding embedding = 10; + + // Por que o sampler on-device guardou este frame. Pode haver mais de um. + repeated Trigger triggers = 11; + + // Privacidade: que redação já foi aplicada NO DISPOSITIVO antes do upload. + Redaction redaction = 12; + + // Chave/valor namespaced para contexto específico do cliente que NÃO pertence + // ao schema do core (id de layout de loja, turno, corredor, etc.). + map attributes = 13; + + // reserved 14 to 19; // exemplo: reserve espaço, nunca reuse números removidos +} + +message Source { + string device_id = 1; // identificador estável de hardware/dispositivo + string site_id = 2; // loja / site / agrupamento de frota + string adapter = 3; // ex. "deepstream", "mqtt", "onnxruntime" + string adapter_version = 4; + string runtime = 5; // descritor livre do runtime +} + +message ModelRef { + string name = 1; + string version = 2; + string artifact_sha256 = 3; // amarra as predições a um build exato do modelo + TaskType task = 4; +} + +message BlobRef { + string sha256 = 1; // endereço de conteúdo — a CHAVE de dedup + string media_type = 2; // ex. "image/jpeg", "image/webp" + uint64 size_bytes = 3; + uint32 width = 4; + uint32 height = 5; + // Localização já conhecida (opcional); se vazio, o core resolve/faz upload. + string uri = 6; +} + +enum TaskType { + TASK_TYPE_UNSPECIFIED = 0; + TASK_TYPE_CLASSIFICATION = 1; + TASK_TYPE_DETECTION = 2; + TASK_TYPE_INSTANCE_SEGMENTATION = 3; + TASK_TYPE_SEMANTIC_SEGMENTATION = 4; + TASK_TYPE_KEYPOINTS = 5; + TASK_TYPE_OBB = 6; // oriented bounding box +} + +// Annotation é a "geometria taggeada": um label mais exatamente UMA geometria, +// selecionada pelo oneof. Adicionar um novo tipo de geometria é mudança aditiva. +message Annotation { + string label = 1; + uint32 label_index = 2; + float confidence = 3; + string track_id = 4; // opcional, para tracking multi-objeto + + oneof geometry { + Classification classification = 10; + BoundingBox bbox = 11; + OrientedBox obox = 12; + Polygon polygon = 13; + Mask mask = 14; + Keypoints keypoints = 15; + } +} + +message Classification { + // Para top-k, repita Annotation; aqui guarda o vetor de scores opcional. + repeated float scores = 1 [packed = true]; +} + +// Todas as coordenadas normalizadas em [0,1] relativas a largura/altura do +// frame — geometria independente de resolução entre câmeras heterogêneas. +message BoundingBox { + float x = 1; // canto superior esquerdo + float y = 2; + float w = 3; + float h = 4; +} + +message OrientedBox { + float cx = 1; + float cy = 2; + float w = 3; + float h = 4; + float angle_rad = 5; +} + +message Polygon { + repeated Point points = 1; +} + +message Mask { + // RLE inline (pequeno) OU um BlobRef para máscaras grandes. + oneof encoding { + string rle = 1; // RLE estilo COCO + BlobRef blob = 2; + } +} + +message Keypoints { + repeated Keypoint points = 1; +} + +message Keypoint { + float x = 1; + float y = 2; + float visibility = 3; // 0 oculto .. 1 visível + string name = 4; +} + +message Point { + float x = 1; + float y = 2; +} + +message Embedding { + repeated float vector = 1 [packed = true]; + uint32 dim = 2; + string model = 3; // qual encoder produziu + bool normalized = 4; // L2-normalizado? +} + +message Trigger { + TriggerReason reason = 1; + float score = 2; // ex. valor de incerteza, distância de drift + string detail = 3; +} + +enum TriggerReason { + TRIGGER_REASON_UNSPECIFIED = 0; + TRIGGER_REASON_LOW_CONFIDENCE = 1; + TRIGGER_REASON_HIGH_ENTROPY = 2; + TRIGGER_REASON_DRIFT = 3; // OOD vs distribuição de treino + TRIGGER_REASON_NOVELTY = 4; + TRIGGER_REASON_FAILURE_HEURISTIC = 5; // ex. obstrução, nenhuma detecção + TRIGGER_REASON_RESERVOIR = 6; // amostra aleatória de baseline + TRIGGER_REASON_MANUAL = 7; + TRIGGER_REASON_DISAGREEMENT = 8; // modelo vs sinal secundário +} + +message Redaction { + bool applied = 1; + RedactionMethod method = 2; + repeated BoundingBox regions = 3; // o que foi borrado/mascarado +} + +enum RedactionMethod { + REDACTION_METHOD_UNSPECIFIED = 0; + REDACTION_METHOD_NONE = 1; + REDACTION_METHOD_FACE_BLUR = 2; + REDACTION_METHOD_FULL_BODY_BLUR = 3; + REDACTION_METHOD_PIXELATE = 4; +} + +// ============================================================================= +// AdapterCapabilities — anunciado UMA vez quando o adapter conecta (handshake), +// NÃO por amostra. O sampler do core lê isso e seleciona a política de sampling +// mais rica que o adapter consegue sustentar, degradando com elegância quando +// um sinal não existe. +// ============================================================================= +message AdapterCapabilities { + string adapter = 1; + string adapter_version = 2; + string schema_version = 3; + + repeated TaskType supported_tasks = 4; + + bool provides_confidence = 5; + bool provides_embedding = 6; + uint32 embedding_dim = 7; + bool provides_raw_frame = 8; + bool provides_thumbnail = 9; + bool can_redact_on_device = 10; + + // Transporte que o adapter fala com o collector local. + string transport = 11; // "uds", "grpc", "mqtt", ... + + // Taxa máxima de amostras que o adapter sustenta sem backpressure. + float max_sample_rate_hz = 12; +} diff --git a/scripts/prepare-release.ps1 b/scripts/prepare-release.ps1 new file mode 100644 index 0000000..c69d80c --- /dev/null +++ b/scripts/prepare-release.ps1 @@ -0,0 +1,184 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true, Position = 0)] + [ValidatePattern('^\d+\.\d+\.\d+([a-zA-Z0-9.-]+)?$')] + [string]$Version, + + [switch]$SkipChecks, + [switch]$NoCommit, + [switch]$NoTag, + [switch]$DryRun +) + +$ErrorActionPreference = "Stop" + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +Set-Location $RepoRoot + +$TagName = "v$Version" +$Today = Get-Date -Format "yyyy-MM-dd" +$PyprojectPath = Join-Path $RepoRoot "pyproject.toml" +$ChangelogPath = Join-Path $RepoRoot "CHANGELOG.md" + +function Invoke-CommandStep { + param( + [Parameter(Mandatory = $true)] + [string]$Label, + + [Parameter(Mandatory = $true)] + [string]$Command, + + [string[]]$Arguments = @() + ) + + $rendered = @($Command) + $Arguments + Write-Host "==> $Label" + Write-Host " $($rendered -join ' ')" + + if ($DryRun) { + return + } + + & $Command @Arguments + if ($LASTEXITCODE -ne 0) { + throw "Command failed: $($rendered -join ' ')" + } +} + +function Write-Utf8File { + param( + [Parameter(Mandatory = $true)] + [string]$Path, + + [Parameter(Mandatory = $true)] + [string]$Content + ) + + $encoding = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, $Content, $encoding) +} + +function Assert-CleanTrackedWorktree { + $status = git status --porcelain --untracked-files=no + if ($LASTEXITCODE -ne 0) { + throw "Unable to inspect git status." + } + + if ($status) { + throw "Tracked files have uncommitted changes. Commit or stash them before preparing a release." + } +} + +function Update-PyprojectVersion { + $content = Get-Content -Raw $PyprojectPath + $pattern = '(?m)^version = "([^"]+)"$' + + if ($content -notmatch $pattern) { + throw "Could not find project version in pyproject.toml." + } + + $currentVersion = $Matches[1] + if ($currentVersion -eq $Version) { + throw "pyproject.toml is already at version $Version." + } + + $regex = [regex]::new($pattern) + $updated = $regex.Replace($content, "version = `"$Version`"", 1) + + Write-Host "==> Update pyproject.toml version" + Write-Host " $currentVersion -> $Version" + + if (-not $DryRun) { + Write-Utf8File $PyprojectPath $updated + } +} + +function Update-Changelog { + if (-not (Test-Path $ChangelogPath)) { + throw "CHANGELOG.md does not exist." + } + + $content = Get-Content -Raw $ChangelogPath + if ($content -match "(?m)^## \[$([regex]::Escape($Version))\]") { + throw "CHANGELOG.md already contains a section for $Version." + } + + $pattern = '(?s)## \[Unreleased\]\r?\n(?.*?)(?=\r?\n## \[|\z)' + $match = [regex]::Match($content, $pattern) + if (-not $match.Success) { + throw "Could not find an Unreleased section in CHANGELOG.md." + } + + $body = $match.Groups["body"].Value.Trim() + if ([string]::IsNullOrWhiteSpace($body) -or $body -eq "- Nothing yet.") { + $body = "- No changes documented." + } + + $replacement = "## [Unreleased]`r`n`r`n- Nothing yet.`r`n`r`n## [$Version] - $Today`r`n`r`n$body`r`n" + $regex = [regex]::new($pattern) + $updated = $regex.Replace($content, $replacement, 1) + + Write-Host "==> Update CHANGELOG.md" + Write-Host " Move Unreleased notes to $Version" + + if (-not $DryRun) { + Write-Utf8File $ChangelogPath $updated + } +} + +function Assert-TagDoesNotExist { + git rev-parse -q --verify "refs/tags/$TagName" *> $null + if ($LASTEXITCODE -eq 0) { + throw "Tag $TagName already exists." + } +} + +function Test-BuildArtifacts { + $artifactPaths = Get-ChildItem -Path (Join-Path $RepoRoot "dist") -File -Filter "visionpack-$Version*" | + ForEach-Object { $_.FullName } + + if (-not $artifactPaths) { + throw "No dist artifacts found for version $Version." + } + + Invoke-CommandStep "Validate distribution metadata" "uvx" (@("twine", "check") + $artifactPaths) +} + +if ($NoCommit -and -not $NoTag) { + throw "Use -NoTag when using -NoCommit; otherwise the tag would not include the release changes." +} + +if (-not $DryRun) { + Assert-CleanTrackedWorktree +} +Assert-TagDoesNotExist +Update-PyprojectVersion +Update-Changelog + +if (-not $SkipChecks) { + Invoke-CommandStep "Run Ruff" "uv" @("run", "ruff", "check", ".") + Invoke-CommandStep "Run unit tests" "uv" @("run", "python", "-m", "unittest", "discover", "-s", "tests", "-q") +} + +Invoke-CommandStep "Build source distribution and wheel" "uv" @("build") + +if (-not $DryRun) { + Test-BuildArtifacts +} + +if (-not $NoCommit) { + Invoke-CommandStep "Stage release files" "git" @("add", "pyproject.toml", "CHANGELOG.md") + Invoke-CommandStep "Create release commit" "git" @("commit", "-m", "Release $TagName") +} + +if (-not $NoTag) { + Invoke-CommandStep "Create release tag" "git" @("tag", $TagName) +} + +Write-Host "" +Write-Host "Release $TagName is prepared." +Write-Host "Next steps:" +Write-Host " git push origin HEAD" +Write-Host " git push origin $TagName" +Write-Host " gh release create $TagName --draft --title `"$TagName`" --notes-file CHANGELOG.md" +Write-Host " Publish the GitHub Release when ready; the publish workflow will upload to PyPI." From adc18d2464b1a8af99a263bb35197424637fea8e Mon Sep 17 00:00:00 2001 From: CaioWing Date: Mon, 15 Jun 2026 19:00:15 -0300 Subject: [PATCH 2/3] Release v0.0.1 --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d9066..4a1fa83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to VisionPack are tracked here. - Nothing yet. +## [0.0.1] - 2026-06-15 + +- No changes documented. + ## [0.1.0] - 2026-06-04 - Initial PyPI-ready package metadata, CLI entry points, build workflow, and release publishing workflow. diff --git a/pyproject.toml b/pyproject.toml index 293a258..93a1b16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "visionpack" -version = "0.1.0" +version = "0.0.1" description = "DatasetOps for computer vision datasets" readme = "README.md" requires-python = ">=3.11" From 7682d87de6c45d55aa91caaa8c63509c72ea1f26 Mon Sep 17 00:00:00 2001 From: CaioWing Date: Tue, 16 Jun 2026 01:20:08 -0300 Subject: [PATCH 3/3] Refactor documentation structure: .gitignore for design docs --- .gitignore | 5 + docs/DESIGN.md | 997 ---------------------------------------- docs/SPEC-cloud-sync.md | 126 ----- docs/SPEC.md | 124 ----- docs/_config.yml | 8 +- docs/cloud-sync.md | 5 +- docs/internals.md | 19 - docs/quickstart.md | 1 - 8 files changed, 13 insertions(+), 1272 deletions(-) delete mode 100644 docs/DESIGN.md delete mode 100644 docs/SPEC-cloud-sync.md delete mode 100644 docs/SPEC.md delete mode 100644 docs/internals.md diff --git a/.gitignore b/.gitignore index 35c1bd6..e2642bb 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ build/ .vp/ exports/ reports/ + +# Internal design docs — kept local, not published to the site or the repo. +docs/DESIGN.md +docs/SPEC.md +docs/SPEC-cloud-sync.md diff --git a/docs/DESIGN.md b/docs/DESIGN.md deleted file mode 100644 index 00f0e3a..0000000 --- a/docs/DESIGN.md +++ /dev/null @@ -1,997 +0,0 @@ ---- -title: Design Rationale -nav_order: 6 ---- - -# VisionPack — Original Product Specification (PT-BR) - -> This is the original design document that scoped VisionPack. It is preserved -> verbatim as the product vision. For current architecture and status see -> [ARCHITECTURE.md](https://github.com/CaioWing/VisionPack/blob/main/ARCHITECTURE.md); -> for usage see the [CLI Guide]({% link usage.md %}). - -## 1. Objetivo - -Projetar e implementar uma ferramenta open source chamada **VisionPack**, focada em organização, validação, versionamento, compressão e preparação de datasets para pipelines de visão computacional. - -A ferramenta deve resolver problemas reais em times de computer vision: - -- datasets desorganizados -- labels inconsistentes -- versões manuais e irreproduzíveis -- exports quebrados entre YOLO, COCO, CVAT e outros formatos -- splits contaminados entre treino, validação e teste -- compressão improvisada -- dificuldade de rastrear qual dataset treinou qual modelo -- dificuldade de preparar pacotes para anotação e revisão -- pipelines complexas baseadas em scripts soltos - -O produto deve ser útil para pesquisadores, startups, times industriais de visão computacional e equipes que treinam modelos de detecção, segmentação, classificação e tracking. - -A visão do produto é: - -> Um Git/Docker-like para datasets de visão computacional: versionável, validável, comprimível, rastreável e pronto para treino ou anotação. - ---- - -## 2. Princípios de Design - -### 2.1 CLI-first - -A primeira interface deve ser CLI. Não começar por web app. - -A ferramenta precisa funcionar bem em: - -- notebooks -- servidores de treino -- CI/CD -- máquinas locais -- pipelines com Makefile, Airflow, Prefect, Dagster ou GitHub Actions - -### 2.2 Manifesto explícito - -Todo dataset deve ter um arquivo declarativo central: - -```text -visionpack.yaml -``` - -Esse arquivo descreve: - -- nome do dataset -- tipo de tarefa -- classes -- formatos de entrada e saída -- splits -- políticas de validação -- perfis de compressão -- transformações -- integrações - -### 2.3 Dados imutáveis, metadados versionáveis - -Assets brutos, como imagens e vídeos, devem ser tratados como conteúdo imutável, identificados por hash. - -Anotações, splits e transformações devem ser versionáveis. - -A ferramenta não deve depender de “pasta com nome certo” como fonte da verdade. A fonte da verdade deve ser o manifesto + índice interno. - -### 2.4 Interoperabilidade acima de lock-in - -VisionPack não deve tentar substituir CVAT, FiftyOne, DVC, Label Studio, Roboflow, Datumaro ou lakeFS. - -Ele deve atuar como camada de DatasetOps: - -- importa de vários formatos -- valida -- organiza -- versiona -- comprime -- exporta -- prepara treino -- prepara pacotes de anotação -- rastreia linhagem - -### 2.5 Reprodutibilidade - -Deve ser possível responder: - -- qual versão do dataset treinou determinado modelo? -- quais imagens entraram ou saíram entre duas versões? -- quais labels mudaram? -- qual split foi usado? -- quais transforms foram aplicadas? -- qual export gerou determinado artefato? -- houve vazamento entre treino e teste? - ---- - -## 3. Escopo Inicial - -O MVP deve suportar primeiro: - -- imagens -- object detection -- formatos YOLO e COCO -- snapshots locais -- validação básica e intermediária -- compressão para treino e arquivamento -- splits versionados -- export para treino -- pacotes para anotação - -Fora do MVP inicial: - -- vídeo -- tracking -- segmentação avançada -- UI web completa -- storage remoto nativo -- colaboração multiusuário -- deduplicação semântica com embeddings -- integração profunda com Kubernetes - -Esses itens podem entrar depois. - ---- - -## 4. Sintaxe da CLI - -A CLI deve ser clara, previsível e composável. - -### 4.1 Inicialização - -```bash -vp init -vp init --name factory-defects --task detection -``` - -Cria: - -```text -visionpack.yaml -.vp/ -assets/ -annotations/ -exports/ -``` - -### 4.2 Importação - -```bash -vp import ./raw --format yolo -vp import ./coco.json --format coco --images ./images -vp import ./dataset --format auto -``` - -Opções importantes: - -```bash -vp import ./raw \ - --format yolo \ - --task detection \ - --copy hardlink \ - --class-map classes.yaml -``` - -Modos de cópia: - -- `copy`: copia arquivos -- `move`: move arquivos -- `hardlink`: evita duplicação local -- `reference`: apenas referencia caminho externo -- `ingest`: copia para content-addressable store - -### 4.3 Validação - -```bash -vp validate -vp validate --strict -vp validate --fix -vp validate --report reports/validation.html -``` - -Validações iniciais: - -- imagem corrompida -- label sem imagem -- imagem sem label -- classe desconhecida -- bounding box fora dos limites -- bounding box com área zero -- duplicatas exatas -- item presente em mais de um split -- classes ausentes em splits -- schema inválido -- resolução fora de limites configurados - -### 4.4 Estatísticas - -```bash -vp stats -vp stats --by class -vp stats --by split -vp stats --html reports/stats.html -``` - -Deve mostrar: - -- número de imagens -- número de labels -- distribuição por classe -- distribuição por split -- resoluções -- tamanhos de arquivo -- imagens sem anotação -- labels por imagem -- outliers - -### 4.5 Splits - -```bash -vp split create --train 0.8 --val 0.1 --test 0.1 -vp split create --strategy stratified --by class -vp split lock -vp split diff baseline current -``` - -Splits devem ser objetos versionáveis, não apenas pastas. - -### 4.6 Snapshots - -```bash -vp snapshot create -m "baseline inicial" -vp snapshot list -vp snapshot show v1 -vp snapshot restore v1 -``` - -Snapshot deve capturar: - -- manifesto -- índice de assets -- índice de annotations -- splits -- transforms declaradas -- validações executadas -- estatísticas resumidas - -### 4.7 Diff - -```bash -vp diff v1 v2 -vp diff v1 v2 --visual -vp diff v1 v2 --json -``` - -Deve responder: - -- imagens adicionadas/removidas -- labels adicionadas/removidas/modificadas -- classes adicionadas/removidas -- mudanças nos splits -- mudanças de distribuição -- assets duplicados -- possíveis regressões - -### 4.8 Compressão - -```bash -vp pack --profile training -vp pack --profile archive -vp pack --profile review -``` - -Perfis: - -```yaml -pack_profiles: - training: - format: webdataset - shard_size: 1024 - compression: zstd - image_quality: original - - archive: - format: tar.zst - compression_level: 15 - include_raw: true - include_metadata: true - - review: - format: folder - image_quality: 85 - max_resolution: 1600 - include_previews: true -``` - -### 4.9 Exportação - -```bash -vp export --format coco --output exports/coco-v3 -vp export --format yolo --output exports/yolo-v3 -vp export --format webdataset --output exports/train-shards -``` - -### 4.10 Anotação - -```bash -vp annotate prepare --target cvat --split unlabeled -vp annotate prepare --target label-studio --limit 1000 -vp annotate ingest ./annotations-from-cvat --format cvat -vp annotate review -``` - -A ferramenta deve facilitar ciclos de anotação: - -1. selecionar imagens não anotadas ou de baixa confiança -2. empacotar para CVAT/Label Studio -3. ingerir anotações de volta -4. validar -5. comparar com versão anterior -6. criar snapshot - ---- - -## 5. Estrutura de Diretórios - -Estrutura recomendada: - -```text -dataset/ - visionpack.yaml - - .vp/ - db/ - index.duckdb - objects/ - sha256/ - ab/ - cd/ - abcdef... - snapshots/ - v1.json - v2.json - cache/ - logs/ - - assets/ - README.md - - annotations/ - README.md - - exports/ - coco/ - yolo/ - webdataset/ - - reports/ - validation.html - stats.html -``` - -Observação importante: - -A pasta `.vp/objects` deve funcionar como content-addressable store. Arquivos são armazenados por hash, evitando duplicação. - ---- - -## 6. Modelo de Dados - -### 6.1 Asset - -Um asset é uma imagem ou vídeo. - -```json -{ - "id": "asset_01J...", - "sha256": "abc123", - "media_type": "image", - "path": ".vp/objects/sha256/ab/cd/abc123", - "original_path": "raw/img001.jpg", - "width": 1920, - "height": 1080, - "channels": 3, - "format": "jpeg", - "size_bytes": 381022, - "created_at": "2026-06-01T12:00:00Z", - "metadata": { - "camera": "line-4", - "factory": "plant-a" - } -} -``` - -### 6.2 Annotation - -```json -{ - "id": "ann_01J...", - "asset_id": "asset_01J...", - "task": "detection", - "format": "internal", - "objects": [ - { - "class_id": "scratch", - "bbox": { - "x": 120, - "y": 80, - "width": 240, - "height": 140, - "coordinate_system": "xywh_absolute" - }, - "confidence": null, - "attributes": { - "occluded": false - } - } - ], - "source": { - "type": "human", - "tool": "cvat", - "annotator": "operator_1" - }, - "created_at": "2026-06-01T12:05:00Z" -} -``` - -### 6.3 Split - -```json -{ - "id": "split_v3", - "strategy": "stratified", - "sets": { - "train": ["asset_1", "asset_2"], - "val": ["asset_3"], - "test": ["asset_4"] - }, - "locked": true, - "created_at": "2026-06-01T12:10:00Z" -} -``` - -### 6.4 Snapshot - -```json -{ - "version": "v3", - "message": "added reviewed annotations", - "created_at": "2026-06-01T12:15:00Z", - "manifest_hash": "sha256...", - "assets_hash": "sha256...", - "annotations_hash": "sha256...", - "splits_hash": "sha256...", - "parent": "v2", - "stats": { - "assets": 12000, - "annotations": 47000, - "classes": 8 - } -} -``` - ---- - -## 7. Arquivo `visionpack.yaml` - -Exemplo: - -```yaml -name: factory-defects -version: 1 - -task: detection - -classes: - - id: scratch - name: Scratch - - id: dent - name: Dent - - id: stain - name: Stain - -storage: - mode: content-addressed - hash: sha256 - -validation: - require_annotations: false - allow_empty_images: true - bbox: - min_area_px: 4 - allow_out_of_bounds: false - splits: - prevent_leakage: true - duplicates: - exact: warn - perceptual: off - -splits: - default: - strategy: stratified - train: 0.8 - val: 0.1 - test: 0.1 - stratify_by: class - -exports: - yolo: - image_format: jpg - normalized_coordinates: true - coco: - include_empty_images: true - -pack_profiles: - training: - format: webdataset - shard_size: 1024 - compression: zstd - - archive: - format: tar.zst - compression_level: 15 - include_metadata: true - -annotation: - preferred_tool: cvat - review_required: true -``` - ---- - -## 8. Arquitetura Técnica - -### 8.1 Linguagem - -Recomendação inicial: **Python**. - -Motivos: - -- ecossistema forte em computer vision -- fácil integração com PyTorch, OpenCV, PIL, COCO tools -- bom para CLI e SDK -- adoção mais fácil por cientistas de dados - -Bibliotecas sugeridas: - -- `typer` para CLI -- `pydantic` para schemas -- `rich` para output no terminal -- `duckdb` para índice local -- `polars` para análises tabulares -- `pillow` para imagens -- `opencv-python` opcional -- `pyyaml` para config -- `zstandard` para compressão -- `orjson` para JSON rápido - -Acelerações futuras podem ser feitas em Rust via `pyo3`, especialmente para hashing, diff e packing. - -### 8.2 Módulos - -Estrutura de código sugerida: - -```text -visionpack/ - __init__.py - - cli/ - main.py - commands/ - init.py - import_.py - validate.py - stats.py - split.py - snapshot.py - diff.py - export.py - pack.py - annotate.py - - core/ - project.py - manifest.py - asset.py - annotation.py - snapshot.py - split.py - errors.py - - storage/ - object_store.py - local_store.py - hash.py - materialize.py - - index/ - duckdb_index.py - migrations.py - queries.py - - formats/ - base.py - yolo.py - coco.py - cvat.py - label_studio.py - - validation/ - engine.py - checks/ - images.py - annotations.py - bbox.py - splits.py - classes.py - duplicates.py - - packing/ - profiles.py - tar_zst.py - webdataset.py - - diff/ - dataset_diff.py - annotation_diff.py - split_diff.py - - annotate/ - prepare.py - ingest.py - review.py - - reports/ - html.py - json.py - terminal.py - - training/ - torch_dataset.py - datamodule.py - - plugins/ - registry.py -``` - ---- - -## 9. Interfaces - -### 9.1 CLI - -Interface principal. - -Deve ser estável, limpa e scriptável. - -### 9.2 Python SDK - -Exemplo: - -```python -from visionpack import Dataset - -ds = Dataset.open(".") -ds.validate(strict=True) - -snapshot = ds.snapshot("reviewed annotations") -train = ds.export(format="webdataset", split="train") -``` - -### 9.3 Integração com treino - -Deve oferecer helpers para PyTorch: - -```python -from visionpack.training import VisionPackDetectionDataset - -dataset = VisionPackDetectionDataset( - root=".", - version="v3", - split="train", - transforms=my_transforms, -) -``` - -Mas o core não deve depender pesadamente de PyTorch. - -### 9.4 GitHub Action - -Futuro próximo: - -```yaml -- uses: visionpack/validate-action@v1 - with: - strict: true - report: true -``` - ---- - -## 10. Estratégia de Versionamento - -Versionamento deve funcionar por snapshots. - -Cada snapshot referencia hashes de: - -- manifesto -- lista de assets -- annotations -- splits -- transforms -- validações - -Não tentar recriar Git do zero. - -O armazenamento local pode funcionar assim: - -- assets guardados por hash -- annotations normalizadas no índice -- snapshots como JSON -- exports gerados sob demanda -- arquivos derivados podem ser cacheados - -Para datasets muito grandes, permitir modo `reference`, onde assets não são copiados, apenas indexados por caminho + hash. - ---- - -## 11. Estratégia de Compressão - -A compressão precisa ser orientada ao uso. - -### 11.1 Archive - -Para backup e transferência fria: - -```bash -vp pack --profile archive -``` - -Formato: - -- `.tar.zst` -- inclui manifesto -- inclui snapshots -- inclui índice exportável -- inclui assets e annotations - -### 11.2 Training - -Para treino eficiente: - -```bash -vp pack --profile training -``` - -Formato recomendado: - -- WebDataset shards -- `.tar` ou `.tar.zst` -- shards balanceados -- metadados por amostra -- split preservado - -### 11.3 Review - -Para revisão humana: - -```bash -vp pack --profile review -``` - -Gera: - -- imagens reduzidas -- previews -- labels em formato compatível com ferramenta de anotação -- pacote menor para enviar a anotadores - ---- - -## 12. Boas Práticas de Dataset Embutidas - -A ferramenta deve guiar o usuário para boas práticas sem ser paternalista. - -Checks importantes: - -- impedir train/test leakage -- alertar classes raras -- alertar mudanças bruscas de distribuição -- alertar duplicatas -- alertar labels inválidos -- alertar imagens com resolução muito fora da média -- preservar imagens vazias quando configurado -- permitir dataset com negative samples -- gerar relatório de cobertura de anotação -- registrar origem das labels -- diferenciar label humano, label sintético e pseudo-label - ---- - -## 13. Fluxo de Trabalho Ideal - -### 13.1 Criar dataset - -```bash -vp init --name road-damage --task detection -vp import ./raw --format yolo -vp validate -vp stats -vp snapshot create -m "initial import" -``` - -### 13.2 Preparar anotação - -```bash -vp annotate prepare --target cvat --where "annotation_count == 0" --limit 2000 -``` - -### 13.3 Ingerir anotações - -```bash -vp annotate ingest ./cvat-export.zip --format cvat -vp validate --strict -vp diff latest working -vp snapshot create -m "cvat batch 01 reviewed" -``` - -### 13.4 Exportar para treino - -```bash -vp split create --strategy stratified --by class -vp pack --profile training -vp export --format yolo --output exports/yolo-v4 -``` - -### 13.5 Registrar versão usada no modelo - -```bash -vp snapshot tag v4 trained:model-2026-06-01 -``` - ---- - -## 14. Funcionalidades Essenciais do MVP - -Implementar nesta ordem: - -1. `vp init` -2. `vp import` para YOLO -3. índice local com DuckDB -4. leitura de imagens e hashing -5. schema interno de annotation -6. `vp validate` -7. `vp stats` -8. `vp snapshot create/list/show` -9. `vp diff` -10. `vp export --format yolo` -11. `vp export --format coco` -12. `vp pack --profile archive` -13. `vp pack --profile training` - -Não implementar UI web antes disso. - ---- - -## 15. Design de Erros - -Erros devem ser humanos e acionáveis. - -Ruim: - -```text -ValidationError: bbox invalid -``` - -Bom: - -```text -Invalid bounding box in image img_0231.jpg - -Class: scratch -Problem: x + width exceeds image width -Image size: 1280x720 -Box: x=1200, y=200, width=300, height=80 - -Suggested fix: -- clamp boxes with: vp validate --fix bbox.clamp -- or inspect manually with: vp inspect img_0231.jpg -``` - ---- - -## 16. Diferenciais Competitivos - -VisionPack deve se diferenciar por: - -- foco específico em computer vision -- snapshots compreensíveis -- diff de datasets -- validação forte -- compressão orientada a treino/anotação/archive -- integração com formatos existentes -- CLI simples -- uso em CI -- preparação de pacotes para anotação -- rastreabilidade de dataset até modelo - -Não vender como “data lake”, “annotation platform” ou “MLOps completo”. - -Posicionamento: - -> VisionPack is DatasetOps for Computer Vision. - ---- - -## 17. Futuro Pós-MVP - -Funcionalidades futuras: - -- suporte a segmentation masks -- suporte a vídeos e tracking -- perceptual hashing para duplicatas visuais -- embeddings para near-duplicate detection -- UI local para revisão visual -- integração com S3/GCS/Azure -- integração com DVC/lakeFS -- lineage entre dataset e training runs -- dataset cards automáticos -- active learning queue -- pseudo-label management -- reviewer workflow -- plugin para CVAT -- dashboards HTML -- integração com FiftyOne - ---- - -## 18. Critérios de Sucesso - -O projeto é bem-sucedido se um usuário consegue: - -1. importar um dataset YOLO bagunçado -2. descobrir problemas reais com `vp validate` -3. gerar estatísticas úteis -4. criar uma versão reproduzível -5. preparar um pacote para anotação -6. ingerir labels revisados -7. comparar duas versões -8. exportar para treino -9. compactar o dataset para storage ou pipeline -10. rastrear qual versão gerou determinado treino - ---- - -## 19. Pedido para o Agente Implementador - -Construa esse projeto com foco em qualidade de arquitetura, legibilidade e extensibilidade. - -Priorize: - -- schemas fortes -- CLI consistente -- testes de unidade para parsers e validators -- fixtures pequenas de datasets YOLO e COCO -- documentação clara -- erros acionáveis -- separação entre core, formatos, storage e CLI - -Evite: - -- criar web app cedo demais -- acoplar o core a PyTorch -- depender de uma estrutura fixa de pastas como fonte da verdade -- transformar a ferramenta em annotation tool completa -- inventar um formato fechado sem exportadores úteis -- otimizar prematuramente antes do fluxo básico funcionar - -Resultado esperado do primeiro ciclo: - -- pacote Python instalável -- comando `vp` -- suporte mínimo a YOLO detection -- importação, validação, stats, snapshot, diff e export -- README com exemplos reais -- testes cobrindo fluxos principais diff --git a/docs/SPEC-cloud-sync.md b/docs/SPEC-cloud-sync.md deleted file mode 100644 index c266c71..0000000 --- a/docs/SPEC-cloud-sync.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Cloud Sync Spec -parent: Internals -nav_order: 2 ---- - -# VisionPack — Cloud Sync Spec (v1) - -Como o `vp sync` associa dados em object stores (S3, GCS) **sem baixar o dataset -inteiro** e **sem duplicar bytes**, mantendo a garantia de integridade e -reprodutibilidade que o resto da ferramenta promete. - -Escopo da v1: **same-provider** (source e target no mesmo provedor — tudo S3 ou -tudo GCS). Cross-cloud (S3↔GCS) fica para um adapter de transferência futuro. - -## O princípio - -A identidade de um asset é **sempre o `sha256` do conteúdo** — igual ao caminho -local. Não existe identidade alternativa por etag/crc32c. Toda a complexidade que -um modelo "identidade por fingerprint" traria (estados provisórios, staging, -verificação, reconciliação) é evitada por uma única decisão: - -> O `sha256` é calculado lendo cada objeto **exatamente uma vez**, e **nunca mais**. - -Não há como endereçar conteúdo sem ver o conteúdo. A meta nunca foi "nunca ler"; -é **não reler** no re-sync e **não persistir** localmente quando não for pedido. - -## A regra do etag - -O insight que mantém isso simples e robusto: - -> `etag`/`crc32c` é confiável como **"esse objeto mudou?"** (mesma chave) e frágil -> como **"que objeto é esse?"** (entre chaves). Usamos só o primeiro. - -Mesma chave + mesmo etag ⇒ conteúdo inalterado (garantido em S3 e GCS). Isso é -tudo que o re-sync precisa. **O etag nunca é comparado entre chaves diferentes** — -então ambiguidade de multipart, objetos cifrados (SSE-KMS) e colisão de crc32c -**nunca decidem nada**. Eles não são identidade; são um sino de "mudou". - -## Fluxo do `vp sync` - -1. Lista o metadata do(s) source(s) e do target (só nomes, `size`, `etag`) — zero - corpo. -2. Para cada objeto, consulta o cache `blob_cache(uri, etag, size) → sha256`: - - **bate** ⇒ pula. Zero leitura, zero download. - - **não bate** (novo ou mudou) ⇒ lê **uma vez em streaming**, computa o `sha256` - na passada (sem tocar o disco), grava no cache. -3. Materializa os bytes conforme o `copy` da source (abaixo) e grava o `Asset` no - índice (`sha256` agora conhecido; `width`/`height`/`phash` podem ficar NULL até - um pass que precise de pixel). - -Idempotente: re-rodar re-lista, os etags batem, o delta é vazio, nada é lido nem -copiado. Vários sources caindo no mesmo target deduplicam pela chave de conteúdo. - -## Modos de cópia (`copy:`) - -Same-provider, sem operação irreversível na v1: - -| modo | bytes | acoplamento | uso | -|---|---|---|---| -| `copy` (default cloud) | `CopyObject`/`rewrite` **server-side** para `target/objects/sha256///` | target autossuficiente, dedup global | caso comum | -| `reference` | nenhum movimento; o índice aponta para o objeto do source | depende do source vivo | sources que você controla e quer custo zero | -| `ingest` | baixa para o CAS local `.vp/objects/` | offline/edge | trabalho local | - -**`move` não existe na v1.** Era a única operação irreversível e a fonte da maior -parte do risco (apagar a origem com base num sinal não verificado). Quem precisa -drenar um bucket de staging usa `copy` + uma *lifecycle policy* da própria nuvem — -mais simples e sem risco do nosso lado. - -Em `copy`, os bytes **não passam pelo cliente** (a cópia é server-side, dentro do -provedor). O cliente só leu o objeto uma vez, no passo 2, para o hash. - -## Export - -- **Local (`hardlink`, default quando o CAS é local):** o diretório de export - aponta para os inodes do CAS — **zero bytes extras**. (Substitui o `shutil.copy2` - incondicional de hoje, que duplica cada imagem exportada.) -- **Cloud (`manifest`):** escreve labels + `manifest.jsonl` de `(uri, label, set)` - e, opcionalmente, monta `target/export//` por cópia server-side. O trainer - streama do bucket; **zero bytes locais**. - -Split é **network-free** nos dois casos — opera só sobre o índice (ids derivados de -`sha256`, classe primária, phash). Nenhum download para splitar. - -## Por que é robusto - -- **Identidade é sempre o hash real** ⇒ dedup exato, split reproduzível entre - máquinas e caminhos de ingestão, proveniência honesta. Sem estado provisório, - sem promoção tardia, sem reconciliação retroativa. -- **O sinal barato (etag) só é usado onde é 100% seguro** (mudança na mesma chave). -- **Nenhuma operação irreversível na v1** (`move` fica de fora). -- **Re-sync não relê** ⇒ o custo recorrente é uma listagem de metadata. - -Custo honesto: a **primeira** vez que um objeto é visto, ele é lido uma vez -(streaming, sem persistir). Se isso pesar em escala, a otimização é um worker que -roda o hash **in-region na nuvem** e devolve só o `sha256` — mas isso é tier pago e -fica fora da v1. O OSS lê uma vez do cliente e pronto. - -## Impacto no código (mínimo) - -- `Asset.sha256` passa a ser preenchível-lazy (NULL até a primeira leitura para - sources `reference`/cloud); nenhum tipo novo de identidade. -- `Resolver` ganha `stat(uri) -> {size, etag}` (metadata-only, fallback) e - `server_copy(src_uri, dst_uri)`. `read_bytes` continua sendo o caminho de hash. - `list_files` já devolve `size`+`etag` por objeto na **mesma listagem** - (`find(detail=True)`), então o re-sync não faz um HEAD por objeto. -- Credenciais/região declaradas no `visionpack.yaml` (`credentials:`, `region:`) - são repassadas ao filesystem do provedor via `storage_options` do fsspec; o - default continua sendo auth de ambiente (env/instance-role). -- Nova tabela `blob_cache(uri, etag, size, sha256)` no índice SQLite. -- `CopyMode` ganha `reference` para cloud; `move` não entra. -- `target:` no `visionpack.yaml` (uri + layout content-addressed). - -Sem staging, sem ledger, sem gate de verificação. É o `git`-para-cloud: hash uma -vez, content-address, reusa para sempre. - -## Sequência de PRs - -1. ✅ `Resolver.stat` + `FsspecResolver` (list/stat metadata-only) + `blob_cache` - de re-sync. Habilita `vp sync --dry-run` sobre S3/GCS sem baixar nada. -2. ✅ `server_copy` + modos `copy`/`reference` + `target:` no yaml → sync - cloud-internal ponta a ponta. (YOLO; COCO/imagefolder remoto ficam para depois.) -3. ✅ Export `hardlink` local + `manifest` cloud (`AssetMaterializer`): assets - locais são hardlinkados do CAS (zero bytes extras); assets remotos viram - `manifest.jsonl` de `(image, uri, ...)` sem baixar nada. Vale para os três - exporters de diretório (yolo/coco/imagefolder); `pack` segue local-only. diff --git a/docs/SPEC.md b/docs/SPEC.md deleted file mode 100644 index 080499f..0000000 --- a/docs/SPEC.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: Core Spec -parent: Internals -nav_order: 1 ---- - -# VisionPack — Sample Envelope Spec (v1) - -Este documento define o contrato canônico da plataforma e as regras que mantêm -ele estável e generalizável entre runtimes, transportes e hardwares diferentes. -O schema vive em `sample_envelope.proto`. - -## O contrato como narrow waist - -O `SampleEnvelope` é a única coisa que o core entende. Tudo a montante (como o -frame foi obtido) e a jusante (para onde vai) é adaptador. A regra inviolável: -nenhuma especificidade de plataforma pode vazar para dentro do schema do core. -Se você sentir vontade de adicionar um campo `deepstream_*` ou `if runtime ==`, -isso é sinal de adaptador ou capability faltando — não de exceção no contrato. - -Por que Protobuf: codegen cross-language (você gera o stub para Python, C++, -Go, Rust a partir do mesmo `.proto`), wire format compacto para links de loja -metidos, e compatibilidade evolutiva embutida. O JSON canônico continua -disponível para debug. - -## Regras de versionamento - -A compatibilidade evolutiva é o que permite atualizar o core e os adapters em -ritmos diferentes — essencial numa frota de milhares de dispositivos com OTA. - -Dentro de `visionpack.v1`, só mudanças aditivas. Concretamente: nunca renumere -um campo; nunca reutilize um número já usado; campo removido vira `reserved` -(reservando número e nome); campo novo entra com número novo e semântica -opcional. Como proto3 preserva campos desconhecidos, um core antigo ingere -envelopes de um adapter mais novo ignorando o que não reconhece (forward-compat), -e um adapter antigo continua válido para um core novo (backward-compat). - -Mudança que quebra de fato — remover semântica de um campo existente, mudar tipo, -alterar unidade — exige bump de pacote para `visionpack.v2`, rodando lado a lado -com v1 durante a transição. O campo `schema_version` ("1.3") serve para debug, -filtro de log e gating de capability em runtime, separado da versão de pacote. - -## Contrato de capabilities e degradação graciosa - -Plataformas expõem sinais diferentes. O `AdapterCapabilities` é anunciado uma -vez no handshake (não por amostra) e diz ao core o que aquele adapter consegue -fornecer. O sampler então escolhe a política mais rica sustentável e cai para a -próxima quando o sinal não existe: - -| Sinal disponível | Política de sampling escolhida | -|-----------------------------|---------------------------------------------| -| `provides_embedding` | drift / novidade (distância OOD no espaço) | -| `provides_confidence` | incerteza (baixa confiança, entropia alta) | -| nenhum dos dois | reservoir com rate-limit (baseline) | -| `can_redact_on_device` | habilita política de privacidade (blur) | - -Heurísticas de falha (obstrução, nenhuma detecção, disagreement) entram quando o -adapter as expõe via `Trigger`. O ponto central: nunca *exigir* o sinal mais -rico — exigir embedding deixaria de fora a maioria dos usuários no dia um. - -## Lazy hydration e dedup - -O envelope carrega **referências**, não bytes. `BlobRef.sha256` é o endereço de -conteúdo e a chave de dedup: blobs idênticos entre frames, dispositivos, lojas -e até clientes sobem uma vez só. Na primeira passada o adapter sobe metadata + -embedding + thumbnail; o frame em resolução cheia só é hidratado quando a -curadoria na nuvem decide que aquela amostra vale anotação. Resultado: banda -proporcional ao valor, não ao volume. - -## Privacidade - -`Redaction` registra o que foi tratado no dispositivo antes de qualquer upload — -crítico em varejo, onde rostos de clientes não podem sair do edge crus. O core -pode recusar envelopes sem redação quando a política do site exigir. - -## Exemplo (JSON canônico do proto3, camelCase) - -```json -{ - "schemaVersion": "1.0", - "envelopeId": "018f3a2b-7c41-7e9a-bd02-1f9c5a6e0d11", - "capturedAt": "2026-06-06T14:22:31Z", - "source": { - "deviceId": "jetson-loja042-cam03", - "siteId": "loja-042", - "adapter": "deepstream", - "adapterVersion": "0.3.1", - "runtime": "deepstream-7.1/jetpack-6.0" - }, - "model": { - "name": "cart-detector", - "version": "11n-int8", - "artifactSha256": "9b1c...e7", - "task": "TASK_TYPE_DETECTION" - }, - "frame": { - "sha256": "4f2a...c9", - "mediaType": "image/jpeg", - "sizeBytes": 184320, - "width": 1920, - "height": 1080 - }, - "thumbnail": { "sha256": "a07d...11", "mediaType": "image/webp", "width": 320, "height": 180 }, - "predictions": [ - { - "label": "product", - "labelIndex": 3, - "confidence": 0.41, - "trackId": "t-9182", - "bbox": { "x": 0.512, "y": 0.337, "w": 0.084, "h": 0.121 } - } - ], - "embedding": { "dim": 256, "model": "yolo-cls-head", "normalized": true, "vector": ["..."] }, - "triggers": [ - { "reason": "TRIGGER_REASON_LOW_CONFIDENCE", "score": 0.41 }, - { "reason": "TRIGGER_REASON_DRIFT", "score": 0.83, "detail": "cosine vs centroid" } - ], - "redaction": { "applied": true, "method": "REDACTION_METHOD_FACE_BLUR" }, - "attributes": { "aisle": "12", "shift": "evening" } -} -``` - -Repare que o `frame` aparece só como `sha256` + dimensões: a amostra acima -trafega em poucos KB, e o JPEG de 180 KB só sobe se a nuvem pedir. diff --git a/docs/_config.yml b/docs/_config.yml index 95b0442..eea7ded 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -29,8 +29,8 @@ search: previews: 3 tokenizer_separator: /[\s/]+/ -# Light, high-contrast reading theme. -color_scheme: light +# Dark reading theme. +color_scheme: dark # Header links (open in a new tab). aux_links: @@ -66,3 +66,7 @@ exclude: - Gemfile - Gemfile.lock - vendor + # Internal design docs — kept local, never published to the site. + - DESIGN.md + - SPEC.md + - SPEC-cloud-sync.md diff --git a/docs/cloud-sync.md b/docs/cloud-sync.md index e36d477..e047d9e 100644 --- a/docs/cloud-sync.md +++ b/docs/cloud-sync.md @@ -36,8 +36,7 @@ pip install "visionpack[azure]" # Azure Blob {: .note } v1 is **same-provider** (S3↔S3 or GCS↔GCS). Cross-cloud transfer (S3↔GCS) is on -the roadmap. The full design is in -[the cloud-sync spec]({% link SPEC-cloud-sync.md %}). +the roadmap. ## Declare remote sources @@ -149,5 +148,5 @@ the delta is empty, nothing is read or copied. That's the whole recurring cost. ## See also -- [Cloud Sync Spec]({% link SPEC-cloud-sync.md %}) — the design and guarantees in full. - [CLI Guide]({% link usage.md %}) — `vp sync` / `vp export` options. +- [Quickstart]({% link quickstart.md %}) — the local-first walkthrough. diff --git a/docs/internals.md b/docs/internals.md deleted file mode 100644 index 8b5bc16..0000000 --- a/docs/internals.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Internals -nav_order: 8 -has_children: true ---- - -# Internals - -Design notes and specifications for how VisionPack works under the hood. Useful if -you're contributing, integrating, or just want to understand the guarantees. - -- **[Core Spec]({% link SPEC.md %})** — the data model, storage, and command - semantics. -- **[Cloud Sync Spec]({% link SPEC-cloud-sync.md %})** — how remote sync stays - efficient and safe (sha256 identity, etag-as-change-detector, server-side copy). - -For the broader architecture, module map, and roadmap, see -[ARCHITECTURE.md](https://github.com/CaioWing/VisionPack/blob/main/ARCHITECTURE.md) -in the repository. diff --git a/docs/quickstart.md b/docs/quickstart.md index a5984ac..8a0e0d4 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -118,4 +118,3 @@ extra bytes. - [CLI Guide]({% link usage.md %}) — every command and option. - [Cloud Sync]({% link cloud-sync.md %}) — do all of this against S3 / GCS / Azure. -- [Design Rationale]({% link DESIGN.md %}) — why VisionPack works the way it does.