package main import ( "encoding/json" "fmt" "math/rand" "time" "hr_receiver/config" "hr_receiver/models" ) const ( aiAnalysisRecordCount = 100 trainingSessionRecordCount = 80 insertBatchSize = 50 ) var ( regionIDs = []uint32{1, 3} sourceTypes = []string{"upload", "cloud"} appNames = []string{"HeartRate Teacher", "HeartRate Console", "HeartRate Admin"} ) func main() { rng := rand.New(rand.NewSource(time.Now().UnixNano())) config.InitConfig() config.ConnectDB() //aiRecords := generateAIAnalysisRecords(rng, aiAnalysisRecordCount) //if err := config.DB.CreateInBatches(aiRecords, insertBatchSize).Error; err != nil { // panic("failed to insert AI analysis mock data: " + err.Error()) //} trainingRecords := generateTrainingSessionRecords(rng, trainingSessionRecordCount) if err := config.DB.CreateInBatches(trainingRecords, insertBatchSize).Error; err != nil { panic("failed to insert training session mock data: " + err.Error()) } //fmt.Printf("成功插入 %d 条 AI 分析记录\n", len(aiRecords)) fmt.Printf("成功插入 %d 条训练会话记录\n", len(trainingRecords)) } func generateAIAnalysisRecords(rng *rand.Rand, count int) []models.AIAnalysisRecord { records := make([]models.AIAnalysisRecord, 0, count) for i := 0; i < count; i++ { records = append(records, generateAIAnalysisRecord(rng)) } return records } func generateAIAnalysisRecord(rng *rand.Rand) models.AIAnalysisRecord { regionID := pickRegionID(rng) sourceType := pickOne(rng, sourceTypes) docxSize := int64(rng.Intn(451*1024) + 50*1024) csvSize := int64(rng.Intn(20*1024) + 70*1024) analysisType := randomAnalysisType(rng) var stepCSVSize int64 if analysisType == "heart_rate_with_steps" { stepCSVSize = int64(rng.Intn(20*1024) + 20*1024) } originalFileSize := docxSize + csvSize + stepCSVSize compressedDocx := int64(float64(docxSize) * (0.3 + rng.Float64()*0.3)) compressedCSV := int64(float64(csvSize) * (0.22 + rng.Float64()*0.08)) var compressedStepCSV int64 if stepCSVSize > 0 { compressedStepCSV = int64(float64(stepCSVSize) * (0.22 + rng.Float64()*0.08)) } compressedContentSize := compressedDocx + compressedCSV + compressedStepCSV promptTemplateSize := 1500 + rng.Intn(500) inputSizeBytes := int(compressedContentSize) + promptTemplateSize outputSizeBytes := rng.Intn(22*1024) + 3*1024 inputTokens := inputSizeBytes / (3 + rng.Intn(2)) outputTokens := outputSizeBytes / (3 + rng.Intn(2)) tokenLatency := int64(15 + rng.Intn(26)) durationMs := 500 + int64(outputTokens)*tokenLatency if durationMs > 60000 { durationMs = 60000 - int64(rng.Intn(5000)) } uploadTime := randomRecentMillis(rng, 90) totalCost, costJSON := buildMockCost(inputTokens, outputTokens) return models.AIAnalysisRecord{ RegionID: ®ionID, SourceType: sourceType, AnalysisType: analysisType, AnalysisResult: "mock analysis result", CostJSON: costJSON, TotalCost: totalCost, InputTokens: inputTokens, OutputTokens: outputTokens, InputSizeBytes: inputSizeBytes, OutputSizeBytes: outputSizeBytes, DurationMs: durationMs, OriginalFileSize: originalFileSize, CompressedContentSize: compressedContentSize, UploadTime: uploadTime, } } func generateTrainingSessionRecords(rng *rand.Rand, count int) []models.MqttTrainingSessionRecord { records := make([]models.MqttTrainingSessionRecord, 0, count) sessionCount := count / 2 if sessionCount == 0 { sessionCount = 1 } for i := 0; i < sessionCount; i++ { sessionRecords := generateTrainingSessionPair(rng, i) records = append(records, sessionRecords...) if len(records) >= count { break } } if len(records) > count { records = records[:count] } return records } func generateTrainingSessionPair(rng *rand.Rand, index int) []models.MqttTrainingSessionRecord { regionID := pickRegionID(rng) appName := pickOne(rng, appNames) testID := fmt.Sprintf("mock-test-%04d", index+1) startedAt := randomRecentMillis(rng, 60) publishedAt := startedAt + int64(rng.Intn(30_000)) startRecord := models.MqttTrainingSessionRecord{ Identifier: fmt.Sprintf("mock-heartrate-%d-%s", regionID, testID), Topic: fmt.Sprintf("/whgw/v2/region/test/%d", regionID), TestID: testID, EventType: "start_test", RegionID: regionID, FlavorType: "heartrate", RawFlavor: "heartrate", AppName: appName, StartedAt: int64Ptr(startedAt), PublishedAt: publishedAt, ReceivedAt: publishedAt + int64(rng.Intn(3000)), RawPayload: buildTrainingPayloadJSON(testID, regionID, appName, "start_test", publishedAt), } records := []models.MqttTrainingSessionRecord{startRecord} // 保留少量“开始未结束”的样本,用于测试进行中统计。 if rng.Intn(100) < 15 { return records } durationMs := int64((5+rng.Intn(41))*60*1000 + rng.Intn(60_000)) endedAt := startedAt + durationMs stopPublishedAt := endedAt + int64(rng.Intn(20_000)) stopRecord := models.MqttTrainingSessionRecord{ Identifier: fmt.Sprintf("mock-heartrate-%d-%s-stop", regionID, testID), Topic: fmt.Sprintf("/whgw/v2/region/test/%d", regionID), TestID: testID, EventType: "stop_test", RegionID: regionID, FlavorType: "heartrate", RawFlavor: "heartrate", AppName: appName, StartedAt: int64Ptr(startedAt), EndedAt: int64Ptr(endedAt), PublishedAt: stopPublishedAt, ReceivedAt: stopPublishedAt + int64(rng.Intn(3000)), RawPayload: buildTrainingPayloadJSON(testID, regionID, appName, "stop_test", stopPublishedAt), } return append(records, stopRecord) } func buildMockCost(inputTokens, outputTokens int) (float64, string) { inputCost := float64(inputTokens) * 0.000002 outputCost := float64(outputTokens) * 0.000008 totalCost := inputCost + outputCost payload := map[string]float64{ "inputCost": inputCost, "outputCost": outputCost, } data, _ := json.Marshal(payload) return totalCost, string(data) } func buildTrainingPayloadJSON(testID string, regionID uint32, appName, eventType string, publishedAt int64) string { payload := map[string]string{ "appName": appName, "eventType": eventType, "flavor": "heartrate", "regionId": fmt.Sprintf("%d", regionID), "testId": testID, "timestamp": time.UnixMilli(publishedAt).UTC().Format("2006-01-02T15:04:05.000Z"), "type": "mqtt_test", } data, _ := json.Marshal(payload) return string(data) } func randomAnalysisType(rng *rand.Rand) string { if rng.Intn(100) < 30 { return "heart_rate_with_steps" } return "heart_rate_only" } func randomRecentMillis(rng *rand.Rand, days int) int64 { return time.Now(). Add(-time.Duration(rng.Intn(days*24)) * time.Hour). Add(-time.Duration(rng.Intn(60)) * time.Minute). UnixMilli() } func pickRegionID(rng *rand.Rand) uint32 { return regionIDs[rng.Intn(len(regionIDs))] } func pickOne(rng *rand.Rand, values []string) string { return values[rng.Intn(len(values))] } func int64Ptr(v int64) *int64 { return &v }