Files
ai-agent/cmd/testdata/main.go
T
t 18c9354095 refactor: 将客服后端重构为宿主可嵌入模块
- 注入数据库、运行时配置、统一响应、文件存储和平台 AI 能力,补充业务读写工具与客户快捷操作契约。

- 移除模块内重复的组织、客户、工单、标签、技能、旧工作流、MCP 和迁移实现,将身份权限与业务主体交由宿主管理。

- 使用 libSQL 重构向量存储,并完善图片消息、访客身份、排队调度、企业微信和支持聊天页面。

- 统一 HTTP、DTO 与 WebSocket 的 snake_case 协议,补齐模块初始化、业务动作和公共载荷等回归测试。
2026-08-28 22:23:13 +08:00

196 lines
5.0 KiB
Go

package main
import (
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/aiagent"
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/aiconfig"
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/channel"
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/kb"
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/quickreply"
"code.tczkiot.com/wlw/ai-agent/cmd/testdata/seedlang"
"code.tczkiot.com/wlw/ai-agent/internal/bootstrap"
"code.tczkiot.com/wlw/ai-agent/internal/models"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
"flag"
"fmt"
"log/slog"
"os"
"strings"
"github.com/mlogclub/simple/sqls"
"gorm.io/gorm"
gormlogger "gorm.io/gorm/logger"
)
func main() {
if err := run(); err != nil {
slog.Error("init testdata failed", "error", err)
os.Exit(1)
}
}
func run() error {
configPath := flag.String("config", "config/config.yaml", "path to config file")
autoConfirm := flag.Bool("yes", false, "skip confirmation prompt")
langValue := flag.String("lang", string(seedlang.Chinese), "testdata language: zh or en")
flag.Parse()
lang, err := seedlang.Parse(*langValue)
if err != nil {
return err
}
if err := confirmDestructiveAction(*autoConfirm); err != nil {
return err
}
cfg, err := config.Load(*configPath)
if err != nil {
return fmt.Errorf("load config failed: %w", err)
}
db, err := bootstrap.InitDB(cfg.DB)
if err != nil {
return fmt.Errorf("init db failed: %w", err)
}
db = withSilentSQLLogger(db)
sqls.SetDB(db)
slog.Info("connected database success")
droppedTableCount, err := resetAllTables(db, cfg.DB.Type)
if err != nil {
return fmt.Errorf("reset all tables failed: %w", err)
}
slog.Info("reset all tables success", slog.Int("droppedTableCount", droppedTableCount))
if err := db.AutoMigrate(models.Models...); err != nil {
return fmt.Errorf("create testdata schema failed: %w", err)
}
slog.Info("create testdata schema success")
aiConfigResult, err := aiconfig.Init()
if err != nil {
return fmt.Errorf("init ai config failed: %w", err)
}
slog.Info("ai config init success", slog.Bool("skipped", aiConfigResult.Skipped),
slog.String("filePath", aiConfigResult.FilePath),
slog.Int("created", aiConfigResult.Created),
slog.Int("updated", aiConfigResult.Updated))
kbResult, err := kb.Init(lang)
if err != nil {
return fmt.Errorf("init knowledge base failed: %w", err)
}
slog.Info("knowledge base init success",
slog.Int64("faqKnowledgeBaseID", kbResult.FAQKnowledgeBaseID),
slog.Int("createdFAQs", kbResult.CreatedFAQs),
slog.Int("updatedFAQs", kbResult.UpdatedFAQs),
)
aiAgentResult, err := aiagent.Init(lang)
if err != nil {
return fmt.Errorf("init ai agent failed: %w", err)
}
slog.Info("ai agent init success", slog.Int("created", aiAgentResult.Created), slog.Int("updated", aiAgentResult.Updated))
channelResult, err := channel.Init(lang)
if err != nil {
return fmt.Errorf("init channel failed: %w", err)
}
slog.Info("channel init success", slog.Int("created", channelResult.Created), slog.Int("updated", channelResult.Updated))
if err := quickreply.Init(lang); err != nil {
return fmt.Errorf("init quick reply failed: %w", err)
}
slog.Info("quick reply init success")
slog.Info("testdata initialization completed")
return nil
}
func withSilentSQLLogger(db *gorm.DB) *gorm.DB {
if db == nil {
return nil
}
return db.Session(&gorm.Session{Logger: db.Logger.LogMode(gormlogger.Silent)})
}
func confirmDestructiveAction(autoConfirm bool) error {
if autoConfirm {
return nil
}
fmt.Println("警告:该操作会清空当前数据库中的所有表和数据。")
fmt.Print("请输入 INIT 继续,输入其他任意内容取消:")
var input string
if _, err := fmt.Scanln(&input); err != nil {
return fmt.Errorf("read confirmation failed: %w", err)
}
if strings.TrimSpace(input) != "INIT" {
return fmt.Errorf("initialization cancelled")
}
return nil
}
func resetAllTables(db *gorm.DB, dbType string) (int, error) {
tables, err := db.Migrator().GetTables()
if err != nil {
return 0, err
}
filterSystemTables := func(tables []string) []string {
ret := make([]string, 0, len(tables))
for _, table := range tables {
if strings.HasPrefix(table, "sqlite_") {
continue
}
ret = append(ret, table)
}
return ret
}
filtered := filterSystemTables(tables)
if len(filtered) == 0 {
return 0, nil
}
err = withForeignKeyChecksDisabled(db, dbType, func() error {
items := make([]any, 0, len(filtered))
for _, table := range filtered {
items = append(items, table)
}
return db.Migrator().DropTable(items...)
})
if err != nil {
return 0, err
}
return len(filtered), nil
}
func withForeignKeyChecksDisabled(db *gorm.DB, dbType string, fn func() error) error {
var disableSQL string
var enableSQL string
switch dbType {
case "sqlite":
disableSQL = "PRAGMA foreign_keys = OFF"
enableSQL = "PRAGMA foreign_keys = ON"
case "mysql":
disableSQL = "SET FOREIGN_KEY_CHECKS = 0"
enableSQL = "SET FOREIGN_KEY_CHECKS = 1"
default:
return fn()
}
if err := db.Exec(disableSQL).Error; err != nil {
return err
}
defer func() {
_ = db.Exec(enableSQL).Error
}()
return fn()
}