prepare fastapi root layout for server deployment
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from app.core.config import settings
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
|
||||
TRAINING_TABLES = (
|
||||
"training_score_detail",
|
||||
"training_record",
|
||||
"training_submission",
|
||||
"training_order",
|
||||
"training_session",
|
||||
"audit_logs",
|
||||
)
|
||||
|
||||
|
||||
def clear_training_runtime_data(clear_reports: bool = False) -> dict:
|
||||
"""训练数据清理:只清空训练运行表和本地报告文件,不删除病例、用户、评分规则和知识库。"""
|
||||
with SessionLocal() as db:
|
||||
before = {table: _count(db, table) for table in TRAINING_TABLES}
|
||||
for table in TRAINING_TABLES:
|
||||
db.execute(text(f"DELETE FROM {table}"))
|
||||
for table in TRAINING_TABLES:
|
||||
db.execute(text(f"ALTER TABLE {table} AUTO_INCREMENT = 1"))
|
||||
db.commit()
|
||||
after = {table: _count(db, table) for table in TRAINING_TABLES}
|
||||
|
||||
deleted_reports = _clear_reports() if clear_reports else 0
|
||||
return {
|
||||
"database": settings.database_url.split("@")[-1] if "@" in settings.database_url else settings.database_url,
|
||||
"tables_before": before,
|
||||
"tables_after": after,
|
||||
"deleted_report_files": deleted_reports,
|
||||
}
|
||||
|
||||
|
||||
def _count(db, table: str) -> int:
|
||||
"""数据计数:读取目标表当前行数,用于清理前后核对。"""
|
||||
return int(db.execute(text(f"SELECT COUNT(*) FROM {table}")).scalar() or 0)
|
||||
|
||||
|
||||
def _clear_reports() -> int:
|
||||
"""报告清理:只删除 backend/storage/reports 下的文件,保留目录本身。"""
|
||||
report_dir = Path(settings.report_storage_dir)
|
||||
if not report_dir.is_absolute():
|
||||
report_dir = Path(__file__).resolve().parents[1] / report_dir
|
||||
expected_root = Path(__file__).resolve().parents[1] / "storage" / "reports"
|
||||
report_dir = report_dir.resolve()
|
||||
if report_dir != expected_root.resolve():
|
||||
raise RuntimeError(f"refuse to clear unexpected report directory: {report_dir}")
|
||||
report_dir.mkdir(parents=True, exist_ok=True)
|
||||
files = [path for path in report_dir.iterdir() if path.is_file()]
|
||||
for path in files:
|
||||
path.unlink()
|
||||
return len(files)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""命令入口:要求显式确认后才执行训练数据清理。"""
|
||||
parser = argparse.ArgumentParser(description="Clear training runtime data only.")
|
||||
parser.add_argument("--confirm", required=True, help="Must be CLEAR_TRAINING_DATA")
|
||||
parser.add_argument("--reports", action="store_true", help="Also clear local generated PDF reports")
|
||||
args = parser.parse_args()
|
||||
if args.confirm != "CLEAR_TRAINING_DATA":
|
||||
raise SystemExit("confirmation mismatch; use --confirm CLEAR_TRAINING_DATA")
|
||||
print(clear_training_runtime_data(clear_reports=args.reports))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user