Add a first-class office-document capability ALONGSIDE the ComfyUI/GPU creative
pipeline: structured content (typed template fields, filled by a person or the
AI) → a pure-Python renderer → a real .pdf/.docx/.xlsx/.pptx/.md. No graph, no
GPU. Orthogonal subsystem — not bolted onto graphs.
- middleware/doc_render.py: one neutral IR per archetype (doc/sheet/deck) and
exactly one renderer per format (DRY). PDF via WeasyPrint (full-CSS monochrome
print style) with a self-contained pure-Python PDF fallback (valid %PDF, zero
native deps — so CI/model-less pods still render). DOCX/XLSX/PPTX via
python-docx/openpyxl/python-pptx.
- middleware/documents.py: one declarative CATALOG of 22 common templates
(Documents 15, Spreadsheets 4, Presentations 3). Each template's typed fields
drive the form, the AI-fill JSON, and the renderer inputs (one schema). Per-org
store (orgs/<org>/documents, atomic index.json + <id>/doc.json), rendered on
demand. Endpoints (/v1 house style): GET /v1/documents, POST
/v1/documents/generate, GET /v1/documents/library, GET|PATCH|DELETE
/v1/documents/{id}, GET /v1/documents/{id}/download?format=. Registered via the
same injected tenancy resolvers as stacks_store.
- AI-fill is a layered enhancement — the form path renders with NO LLM, so a
broken/unauthorized gateway never blocks creation (422 needFields → prefilled
form). Reuses the shipped Chat's working token: the browser sends window.HZ.pk
(publishable pk- key) as the bearer; the backend forwards it fail-closed —
server key, else a gateway-verifiable pk-/RS-JWT; an HS256 session token or
sk-/hk- secret is NEVER forwarded. Model default enso (window.HZ.model).
- studio_home.html: a "Documents" Home tab (searchable catalog + your documents
with Download PDF/Word/Excel/PowerPoint) + describe/fill dialog; replaced the
dead doc/sheet/paper composer placeholders with one "Office documents" card.
- deps: weasyprint/python-docx/openpyxl/python-pptx (requirements.txt) + pango
native libs (Dockerfile). CI builds the image; not built locally.
- tests-unit/documents_test: catalog invariants, full template×format render
matrix asserted by magic numbers, AI-fill parse + fail-closed bearer allowlist,
and the REST surface incl. per-org isolation (44 tests, green).
- version 0.17.24 → 0.18.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
46 lines
1.6 KiB
YAML
46 lines
1.6 KiB
YAML
# Canonical CI/CD config for hanzoai/studio — read by both the hanzoai/ci
|
|
# reusable workflow (.github/workflows/cicd.yml) and platform.hanzo.ai.
|
|
# One image, unit gates, and a main-branch rollout onto the existing
|
|
# `studio` operator Service CR (universe: infra/k8s/operator/crs/studio.yaml).
|
|
|
|
images:
|
|
- name: studio
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
repo: ghcr.io/hanzoai/studio
|
|
|
|
# CI gates. Full requirements (CPU torch) are installed so every import
|
|
# resolves, then the dependency-light unit suites run (auth, tenancy, user
|
|
# manager, prompt server). Inference/execution/GPU suites run out-of-band.
|
|
test:
|
|
- name: unit
|
|
run: |
|
|
command -v uv >/dev/null || curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
uv venv --python 3.11
|
|
uv pip install -r requirements.txt pytest pytest-aiohttp pytest-asyncio
|
|
uv run pytest -q \
|
|
tests-unit/folder_paths_test \
|
|
tests-unit/middleware_test \
|
|
tests-unit/app_test \
|
|
tests-unit/prompt_server_test \
|
|
tests-unit/studio_home_test \
|
|
tests-unit/documents_test
|
|
|
|
# Deploy: roll the freshly-built image onto the studio Service CR.
|
|
deploy:
|
|
cluster: do-sfo3-hanzo-k8s
|
|
namespace: hanzo
|
|
# Quoted to dodge YAML 1.1 boolean coercion of a bare `on:` key.
|
|
"on": [main]
|
|
services:
|
|
- name: studio
|
|
image: studio
|
|
|
|
# KMS (kms.hanzo.ai, Universal Auth) supplies the GHCR push token and the
|
|
# target kubeconfig at run time. Only KMS_CLIENT_ID/KMS_CLIENT_SECRET live in
|
|
# GitHub; everything else is fetched here.
|
|
kms:
|
|
path: /deploy
|
|
environment: prod
|