Add Phase 13 internal accounting model

This commit is contained in:
A R R R Associates
2026-08-22 21:52:44 +05:30
parent ef2b0e1f83
commit 0c0457aaca
15 changed files with 1171 additions and 3 deletions
@@ -0,0 +1,76 @@
"""Phase 13 internal accounting model.
Revision ID: 20260822_internal_accounting_model_p13
Revises: 20260822_accounting_ai_p12
"""
from alembic import op
import sqlalchemy as sa
revision = "20260822_internal_accounting_model_p13"
down_revision = "20260822_accounting_ai_p12"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"accounting_internal_models",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False),
sa.Column("version_label", sa.String(80), nullable=False),
sa.Column("algorithm", sa.String(80), nullable=False, server_default="multinomial_nb_v1"),
sa.Column("status", sa.String(30), nullable=False, server_default="shadow"),
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.false()),
sa.Column("training_examples", sa.Integer(), nullable=False, server_default="0"),
sa.Column("validation_examples", sa.Integer(), nullable=False, server_default="0"),
sa.Column("class_count", sa.Integer(), nullable=False, server_default="0"),
sa.Column("vocabulary_size", sa.Integer(), nullable=False, server_default="0"),
sa.Column("validation_accuracy", sa.Float(), nullable=False, server_default="0"),
sa.Column("validation_macro_recall", sa.Float(), nullable=False, server_default="0"),
sa.Column("validation_top2_accuracy", sa.Float(), nullable=False, server_default="0"),
sa.Column("model_json", sa.Text(), nullable=False),
sa.Column("metrics_json", sa.Text(), nullable=True),
sa.Column("training_summary_json", sa.Text(), nullable=True),
sa.Column("trained_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True),
sa.Column("trained_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
)
for name in ("tenant_id", "version_label", "status", "is_active", "trained_at_utc"):
op.create_index(f"ix_accounting_internal_models_{name}", "accounting_internal_models", [name])
op.create_table(
"accounting_internal_predictions",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False),
sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False),
sa.Column("model_id", sa.Integer(), sa.ForeignKey("accounting_internal_models.id", ondelete="CASCADE"), nullable=False),
sa.Column("source_type", sa.String(30), nullable=False),
sa.Column("source_record_id", sa.Integer(), nullable=False),
sa.Column("source_fingerprint", sa.String(80), nullable=False, server_default=""),
sa.Column("predicted_nature_id", sa.Integer(), sa.ForeignKey("accounting_natures.id", ondelete="SET NULL"), nullable=True),
sa.Column("predicted_probability", sa.Float(), nullable=False, server_default="0"),
sa.Column("top2_json", sa.Text(), nullable=True),
sa.Column("explanation_json", sa.Text(), nullable=True),
sa.Column("shadow_mode", sa.Boolean(), nullable=False, server_default=sa.true()),
sa.Column("applied_to_source", sa.Boolean(), nullable=False, server_default=sa.false()),
sa.Column("final_nature_id", sa.Integer(), sa.ForeignKey("accounting_natures.id", ondelete="SET NULL"), nullable=True),
sa.Column("prediction_correct", sa.Boolean(), nullable=True),
sa.Column("reviewed_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True),
sa.Column("reviewed_at_utc", sa.DateTime(timezone=True), nullable=True),
sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
)
for name in (
"tenant_id", "client_id", "model_id", "source_type", "source_record_id",
"source_fingerprint", "predicted_nature_id", "shadow_mode", "applied_to_source",
"final_nature_id", "prediction_correct", "created_at_utc",
):
op.create_index(
f"ix_accounting_internal_predictions_{name}",
"accounting_internal_predictions",
[name],
)
def downgrade():
op.drop_table("accounting_internal_predictions")
op.drop_table("accounting_internal_models")