"""ml_settings crop-proposer / detector config (#134) Move the WHERE-to-crop detector config (per-proposer enable + weights + conf, plus caps + dedupe IoU) into the DB so it's UI-tunable and announced to the GPU agent in the lease (like the embedder model) — no restart, agent env is now bootstrap-only. All server_defaults are the working values so existing rows + fresh installs crop out-of-the-box with all three proposers ON. Revision ID: 0078 Revises: 0077 Create Date: 2026-07-05 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0078" down_revision: Union[str, None] = "0077" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None _ANATOMY_DEFAULT = ( "https://github.com/aperveyev/booru_yolo/raw/main/models/yolov11m_aa22.pt" ) _PANEL_DEFAULT = "mosesb/best-comic-panel-detection::best.pt" def upgrade() -> None: op.add_column("ml_settings", sa.Column( "detector_person_enabled", sa.Boolean(), nullable=False, server_default=sa.true())) op.add_column("ml_settings", sa.Column( "detector_person_weights", sa.String(512), nullable=False, server_default="yolo11n.pt")) op.add_column("ml_settings", sa.Column( "detector_person_conf", sa.Float(), nullable=False, server_default=sa.text("0.35"))) op.add_column("ml_settings", sa.Column( "detector_anatomy_enabled", sa.Boolean(), nullable=False, server_default=sa.true())) op.add_column("ml_settings", sa.Column( "detector_anatomy_weights", sa.String(512), nullable=False, server_default=_ANATOMY_DEFAULT)) op.add_column("ml_settings", sa.Column( "detector_anatomy_conf", sa.Float(), nullable=False, server_default=sa.text("0.30"))) op.add_column("ml_settings", sa.Column( "detector_panel_enabled", sa.Boolean(), nullable=False, server_default=sa.true())) op.add_column("ml_settings", sa.Column( "detector_panel_weights", sa.String(512), nullable=False, server_default=_PANEL_DEFAULT)) op.add_column("ml_settings", sa.Column( "detector_panel_conf", sa.Float(), nullable=False, server_default=sa.text("0.30"))) op.add_column("ml_settings", sa.Column( "detector_max_figures", sa.Integer(), nullable=False, server_default=sa.text("8"))) op.add_column("ml_settings", sa.Column( "detector_max_components", sa.Integer(), nullable=False, server_default=sa.text("8"))) op.add_column("ml_settings", sa.Column( "detector_max_panels", sa.Integer(), nullable=False, server_default=sa.text("8"))) op.add_column("ml_settings", sa.Column( "detector_max_regions", sa.Integer(), nullable=False, server_default=sa.text("128"))) op.add_column("ml_settings", sa.Column( "detector_dedupe_iou", sa.Float(), nullable=False, server_default=sa.text("0.85"))) def downgrade() -> None: for col in ( "detector_person_enabled", "detector_person_weights", "detector_person_conf", "detector_anatomy_enabled", "detector_anatomy_weights", "detector_anatomy_conf", "detector_panel_enabled", "detector_panel_weights", "detector_panel_conf", "detector_max_figures", "detector_max_components", "detector_max_panels", "detector_max_regions", "detector_dedupe_iou", ): op.drop_column("ml_settings", col)