feat: initial HSAP platform

Huaxu Sentinel Active Safety Platform with embedded algorithm code,
Docker Compose setup, and vendored dataset scaffolds for clone-and-run.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-25 16:59:59 +08:00
commit 7c43b44c57
1619 changed files with 373355 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""将 SQLite 遗留库 manifests/platform.db 迁移到 PostgreSQL。"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "platform"))
from sqlalchemy import create_engine
from sqlalchemy.orm import joinedload, sessionmaker
from as_platform.config import DATABASE_URL, IS_POSTGRES, SQLITE_LEGACY_PATH
from as_platform.db.engine import Base
from as_platform.db.init_db import init_database
from as_platform.db.models import Approval, Job, Permission, Role, User
def main() -> None:
if not IS_POSTGRES:
print("目标 AS_DATABASE_URL 须为 postgresql://…", file=sys.stderr)
sys.exit(1)
if not SQLITE_LEGACY_PATH.is_file():
print(f"无 SQLite 文件: {SQLITE_LEGACY_PATH},跳过")
init_database()
return
sqlite_url = f"sqlite:///{SQLITE_LEGACY_PATH}"
src = create_engine(sqlite_url, future=True)
dst = create_engine(DATABASE_URL, future=True)
SrcSession = sessionmaker(bind=src)
DstSession = sessionmaker(bind=dst)
Base.metadata.create_all(bind=dst)
with DstSession() as db:
if db.query(User).count() > 0:
print("PostgreSQL 已有数据,跳过迁移(可加 --force 清空后重迁)")
if "--force" not in sys.argv:
return
print("清空目标库…")
db.query(Job).delete()
db.query(Approval).delete()
from as_platform.db.models import role_permissions, user_roles
db.execute(user_roles.delete())
db.execute(role_permissions.delete())
db.query(User).delete()
db.query(Role).delete()
db.query(Permission).delete()
db.commit()
order = [Permission, Role, User, Approval, Job]
with SrcSession() as sdb, DstSession() as ddb:
perm_map = {p.id: p for p in sdb.query(Permission).all()}
for p in perm_map.values():
ddb.merge(Permission(id=p.id, code=p.code, name=p.name))
ddb.flush()
for r in sdb.query(Role).options(joinedload(Role.permissions)).all():
nr = Role(id=r.id, code=r.code, name=r.name)
ddb.add(nr)
ddb.flush()
nr.permissions = [ddb.get(Permission, p.id) for p in r.permissions]
for u in sdb.query(User).options(joinedload(User.roles)).all():
nu = User(
id=u.id,
feishu_open_id=u.feishu_open_id,
feishu_union_id=u.feishu_union_id,
name=u.name,
email=u.email,
avatar_url=u.avatar_url,
is_active=bool(u.is_active),
created_at=u.created_at,
updated_at=u.updated_at,
)
ddb.add(nu)
ddb.flush()
nu.roles = [ddb.get(Role, r.id) for r in u.roles]
for a in sdb.query(Approval).all():
ddb.merge(Approval(
id=a.id, status=a.status, action=a.action, action_label=a.action_label,
params_json=a.params_json, note=a.note,
submitted_by_user_id=a.submitted_by_user_id, submitted_by_name=a.submitted_by_name,
submitted_at=a.submitted_at, reviewed_by_user_id=a.reviewed_by_user_id,
reviewed_by_name=a.reviewed_by_name, reviewed_at=a.reviewed_at,
review_comment=a.review_comment, job_id=a.job_id,
executed_at=a.executed_at, result_json=a.result_json,
))
for j in sdb.query(Job).all():
ddb.merge(Job(
id=j.id, status=j.status, action=j.action, params_json=j.params_json,
approval_id=j.approval_id, created_at=j.created_at,
started_at=j.started_at, finished_at=j.finished_at, result_json=j.result_json,
))
ddb.commit()
print("迁移完成 → PostgreSQL")
if __name__ == "__main__":
main()