Introduces second_brain.pipeline_settings — the single-row config row the upcoming web dashboard edits and the workers read at the start of each run. Pinned to id=1 by a CHECK constraint so upserts-by-PK keep the table singleton, and the migration seeds the row with the table's column defaults via INSERT ... ON CONFLICT DO NOTHING. Two consumer groups carved out: - transcription_* fields persist now; future tower-side worker reads them. - extraction_* fields will be read by the existing scheduler in the next commit, which is the actual behavior change Travis cares about today. The settings_store helper centralises get/update + form-parsing (time-of-day, int-or-none) and active-window math so the routes and the scheduler don't reimplement them.
71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
"""v2 second_brain: pipeline_settings table
|
|
|
|
Revision ID: 7b3e8a5c1f29
|
|
Revises: 4a1e2f6c9d10
|
|
Create Date: 2026-05-25 00:00:00.000000
|
|
|
|
Adds a single-row `pipeline_settings` table that the web dashboard edits
|
|
and the workers (current dev-side scheduler + future tower-side transcribe
|
|
worker) read at the start of each run. The transcription_* fields persist
|
|
now but are only consumed once the transcribe worker exists — the
|
|
extraction_* fields are wired into the existing scheduler in this commit.
|
|
|
|
Single-row enforcement: PK is fixed at `id=1` with a CHECK constraint, so
|
|
INSERT-as-upsert-by-PK keeps the table free of stale rows.
|
|
|
|
Schema/permission notes mirror the v1 migration: lovebug lacks CREATE on
|
|
the petalbrain database, so env.py has already bootstrapped the schema —
|
|
this migration just SETs search_path and emits DDL inside it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Sequence
|
|
|
|
from alembic import op
|
|
|
|
revision: str = "7b3e8a5c1f29"
|
|
down_revision: str | Sequence[str] | None = "4a1e2f6c9d10"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.execute("SET search_path TO second_brain")
|
|
|
|
op.execute(
|
|
"""
|
|
CREATE TABLE pipeline_settings (
|
|
id INTEGER PRIMARY KEY DEFAULT 1,
|
|
transcription_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
transcription_active_hours_start TIME,
|
|
transcription_active_hours_end TIME,
|
|
transcription_max_concurrent_gpu_jobs INTEGER NOT NULL DEFAULT 1,
|
|
transcription_max_video_length_seconds INTEGER,
|
|
transcription_max_items_per_run INTEGER NOT NULL DEFAULT 10,
|
|
extraction_enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
extraction_active_hours_start TIME,
|
|
extraction_active_hours_end TIME,
|
|
extraction_max_items_per_run INTEGER NOT NULL DEFAULT 20,
|
|
updated_at TIMESTAMP NOT NULL
|
|
DEFAULT (now() AT TIME ZONE 'UTC'),
|
|
CONSTRAINT pipeline_settings_singleton CHECK (id = 1)
|
|
)
|
|
"""
|
|
)
|
|
|
|
# Seed the singleton row with the table's column defaults. Idempotent
|
|
# via ON CONFLICT so re-running this migration on a partly-applied DB
|
|
# (or a manual cherry-pick) is safe.
|
|
op.execute(
|
|
"""
|
|
INSERT INTO pipeline_settings (id) VALUES (1)
|
|
ON CONFLICT (id) DO NOTHING
|
|
"""
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.execute("SET search_path TO second_brain")
|
|
op.execute("DROP TABLE IF EXISTS pipeline_settings")
|