1
This commit is contained in:
-167
@@ -14,16 +14,6 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
initDatabase(ctx)
|
||||
//// 封面存量迁移:历史固定命名 cover* → UUID jpg(幂等,新库空跑)
|
||||
//if err := service.Dataset.MigrateLegacyCovers(ctx); err != nil {
|
||||
// g.Log().Errorf(ctx, "封面存量迁移失败: %+v", err)
|
||||
//}
|
||||
//// 封面存量尺寸统一:非 1248x704 的压缩覆盖写(幂等,新库空跑)
|
||||
//if err := service.Dataset.CompressExistingCovers(ctx); err != nil {
|
||||
// g.Log().Errorf(ctx, "封面存量压缩失败: %+v", err)
|
||||
//}
|
||||
|
||||
s := g.Server()
|
||||
// Android APK 下载静态托管:app.apkDir 目录下固定文件 observer-latest.apk,
|
||||
// URL 固定 /download/observer-latest.apk(绕过统一响应包装,纯二进制流);
|
||||
@@ -69,160 +59,3 @@ func main() {
|
||||
service.Training.StartBackgroundJobs(ctx)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
// initDatabase 数据初始化:存量库以 schema_version 表版本化迁移(pg 无 PRAGMA,版本落表);
|
||||
// v2 = 删 license.plan_id 列(无业务语义);v3 = 删 plan 表(套餐已配置化,清残留表)。
|
||||
func initDatabase(ctx context.Context) {
|
||||
version := dbVersion(ctx)
|
||||
if version < 2 {
|
||||
// v2:删除 license.plan_id(只留到期时间;HasColumn 检测列存在才 DROP,
|
||||
// 全新库建表已无此列、直接跳过,不丢账号数据)
|
||||
if common.HasColumn(ctx, "license", "plan_id") {
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE license DROP COLUMN plan_id"); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除 license.plan_id 列失败: %+v", err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 2)
|
||||
}
|
||||
if version < 3 {
|
||||
// v3:套餐改 config.yml 配置后清理残留 plan 表(订单快照 payment_order.plan_id 不受影响)
|
||||
if _, err := g.DB().Exec(ctx, "DROP TABLE IF EXISTS plan"); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除残留 plan 表失败: %+v", err)
|
||||
}
|
||||
setDbVersion(ctx, 3)
|
||||
}
|
||||
if version < 8 {
|
||||
// v8:dataset 加训练配置/展示列 + label_task 加 filenames(多选批量标注)。
|
||||
// HasColumn 逐列检测缺失才 ADD COLUMN,全新库建表自带全列直接跳过
|
||||
addCols := []struct{ table, col, ddl string }{
|
||||
{"dataset", "cover", "TEXT"},
|
||||
{"dataset", "description", "TEXT"},
|
||||
{"dataset", "ai_endpoint", "TEXT"},
|
||||
{"dataset", "ai_model", "TEXT"},
|
||||
{"dataset", "train_host", "TEXT"},
|
||||
{"dataset", "train_user", "TEXT"},
|
||||
{"dataset", "train_password", "TEXT"},
|
||||
{"dataset", "train_key", "TEXT"},
|
||||
{"label_task", "filenames", "JSONB"},
|
||||
}
|
||||
for _, c := range addCols {
|
||||
if common.HasColumn(ctx, c.table, c.col) {
|
||||
continue
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE "+c.table+" ADD COLUMN "+c.col+" "+c.ddl); err != nil {
|
||||
g.Log().Fatalf(ctx, "给 %s 加列 %s 失败: %+v", c.table, c.col, err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 8)
|
||||
}
|
||||
if version < 10 {
|
||||
// v10:标注流程简化,撤销候选确认两阶段 —— dataset_image 删 candidates_json 列
|
||||
//(存量候选数据为空直接删;全新库建表已无此列、HasColumn 检测后跳过)
|
||||
if common.HasColumn(ctx, "dataset_image", "candidates_json") {
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE dataset_image DROP COLUMN candidates_json"); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除 candidates_json 列失败: %+v", err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 10)
|
||||
}
|
||||
if version < 11 {
|
||||
// v11:移除模型存档回退机制 —— model_version 删 model_file 列
|
||||
//(模型文件不落表:发布即写 latest.tflite,客户端固定下载;存量库删列、新库建表已无此列自动跳过)
|
||||
if common.HasColumn(ctx, "model_version", "model_file") {
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE model_version DROP COLUMN model_file"); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除 model_file 列失败: %+v", err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 11)
|
||||
}
|
||||
if version < 12 {
|
||||
// v12:清理孤儿字段 —— dataset 删 6 列(AI 标注/训练机 SSH 配置统一走 config.yml 的
|
||||
// localAi/training.ssh,零读写)+ model_version 删 artifact_file(zip 产物布局移除后无人写)
|
||||
// + label_task 删 boxes_file(标注已入库,候选框文件机制废弃)。
|
||||
// HasColumn 逐列检测存在才 DROP,新库建表已无此列直接跳过
|
||||
dropCols := []struct{ table, col string }{
|
||||
{"dataset", "ai_endpoint"},
|
||||
{"dataset", "ai_model"},
|
||||
{"dataset", "train_host"},
|
||||
{"dataset", "train_user"},
|
||||
{"dataset", "train_password"},
|
||||
{"dataset", "train_key"},
|
||||
{"model_version", "artifact_file"},
|
||||
{"label_task", "boxes_file"},
|
||||
}
|
||||
for _, c := range dropCols {
|
||||
if !common.HasColumn(ctx, c.table, c.col) {
|
||||
continue
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE "+c.table+" DROP COLUMN "+c.col); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除 %s.%s 列失败: %+v", c.table, c.col, err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 12)
|
||||
}
|
||||
if version < 13 {
|
||||
// v13:双档位训练 —— model_training + model_version 增 variant 列(s|n,默认 s 存量归 s 档)。
|
||||
// 全新库建表自带该列;存量库 ADD COLUMN(NOT NULL DEFAULT 's' 免回填)。
|
||||
// HasColumn 逐列检测缺失才 ADD COLUMN
|
||||
addCols := []struct{ table, col string }{
|
||||
{"model_training", "variant"},
|
||||
{"model_version", "variant"},
|
||||
}
|
||||
for _, c := range addCols {
|
||||
if common.HasColumn(ctx, c.table, c.col) {
|
||||
continue
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE "+c.table+" ADD COLUMN "+c.col+" VARCHAR(5) NOT NULL DEFAULT 's'"); err != nil {
|
||||
g.Log().Fatalf(ctx, "增加 %s.%s 列失败: %+v", c.table, c.col, err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 13)
|
||||
}
|
||||
if version < 14 {
|
||||
// v14:综合训练(2026-09-09 多物种合并模型)——model_training / model_version
|
||||
// 加 kind(species/combined)+ dataset_ids(JSON 覆盖数据集列表)。
|
||||
// 存量行默认 species 零回填;全新库建表自带全列直接跳过
|
||||
addCols := []struct{ table, col, ddl string }{
|
||||
{"model_training", "kind", "VARCHAR(20) NOT NULL DEFAULT 'species'"},
|
||||
{"model_training", "dataset_ids", "JSONB"},
|
||||
{"model_version", "kind", "VARCHAR(20) NOT NULL DEFAULT 'species'"},
|
||||
{"model_version", "dataset_ids", "JSONB"},
|
||||
}
|
||||
for _, c := range addCols {
|
||||
if common.HasColumn(ctx, c.table, c.col) {
|
||||
continue
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "ALTER TABLE "+c.table+" ADD COLUMN "+c.col+" "+c.ddl); err != nil {
|
||||
g.Log().Fatalf(ctx, "给 %s 加列 %s 失败: %+v", c.table, c.col, err)
|
||||
}
|
||||
}
|
||||
setDbVersion(ctx, 14)
|
||||
}
|
||||
// 死表清理:app_config 全局训练配置表已撤销(配置走 config.yml),存量库残留表启动即删
|
||||
if _, err := g.DB().Exec(ctx, "DROP TABLE IF EXISTS app_config"); err != nil {
|
||||
g.Log().Fatalf(ctx, "删除残留 app_config 表失败: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// dbVersion 读取库版本(schema_version 单行表);首次运行建表并初始化 0。
|
||||
func dbVersion(ctx context.Context) int {
|
||||
if _, err := g.DB().Exec(ctx, "CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL)"); err != nil {
|
||||
g.Log().Fatalf(ctx, "创建 schema_version 表失败: %+v", err)
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "INSERT INTO schema_version (version) SELECT 0 WHERE NOT EXISTS (SELECT 1 FROM schema_version)"); err != nil {
|
||||
g.Log().Fatalf(ctx, "初始化 schema_version 失败: %+v", err)
|
||||
}
|
||||
res, err := g.DB().GetOne(ctx, "SELECT version FROM schema_version")
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, "读取库版本失败: %+v", err)
|
||||
}
|
||||
return res["version"].Int()
|
||||
}
|
||||
|
||||
// setDbVersion 写入库版本。
|
||||
func setDbVersion(ctx context.Context, v int) {
|
||||
if _, err := g.DB().Exec(ctx, "UPDATE schema_version SET version = ?", v); err != nil {
|
||||
g.Log().Fatalf(ctx, "库版本写入失败: %+v", err)
|
||||
}
|
||||
g.Log().Infof(ctx, "数据库初始化完成(version=%d)", v)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user