From a0489a63bb69c773bef5721cb77aa53dec703702 Mon Sep 17 00:00:00 2001 From: Linrador <68631622+Linrador@users.noreply.github.com> Date: Tue, 12 May 2026 10:00:59 +0200 Subject: [PATCH] fixed training root detection --- backend/ai_server.py | 24 +++------------- backend/analyze.go | 2 +- backend/server.go | 68 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 29 deletions(-) diff --git a/backend/ai_server.py b/backend/ai_server.py index d516e05..343bf45 100644 --- a/backend/ai_server.py +++ b/backend/ai_server.py @@ -69,27 +69,11 @@ def resolve_detection_labels_path() -> Path: return p raise RuntimeError(f"DETECTION_LABELS_PATH not found: {p}") - candidates = [ - TRAINING_ROOT / "detection_labels.json", + p = TRAINING_ROOT / "detection_labels.json" + if existing_file(p): + return p.resolve() - # Wenn ai_server.py direkt neben detection_labels.json embedded liegt: - BASE_DIR / "detection_labels.json", - - # Dev-Fallbacks: - BASE_DIR / "ml" / "detection_labels.json", - BASE_DIR.parent / "ml" / "detection_labels.json", - Path.cwd() / "ml" / "detection_labels.json", - Path.cwd() / "backend" / "ml" / "detection_labels.json", - ] - - for p in candidates: - if existing_file(p): - return p.resolve() - - raise RuntimeError( - "detection_labels.json not found. Checked: " - + ", ".join(str(p) for p in candidates) - ) + raise RuntimeError(f"detection_labels.json not found: {p}") def resolve_model_path() -> str: diff --git a/backend/analyze.go b/backend/analyze.go index 1afa952..7ffe4f9 100644 --- a/backend/analyze.go +++ b/backend/analyze.go @@ -63,7 +63,7 @@ const ( // Video-Modus: extrahiert 1 Frame alle N Sekunden. // 1 = jeder Sekunde, 3 = alle 3 Sekunden, 5 = alle 5 Sekunden. - analyzeVideoFrameIntervalSeconds = 2 + analyzeVideoFrameIntervalSeconds = 3 // AI-Server nicht mit tausenden Pfaden auf einmal fluten. analyzeFramePredictBatchSize = 32 diff --git a/backend/server.go b/backend/server.go index be1533a..054b6e2 100644 --- a/backend/server.go +++ b/backend/server.go @@ -298,8 +298,14 @@ func startAIServer(ctx context.Context) (*aiServerProcess, error) { exeDir = filepath.Dir(exePath) } - defaultProdModel := filepath.Join(exeDir, "generated", "training", "detector", "model", "best.pt") - scriptDirModel := filepath.Join(scriptDir, "generated", "training", "detector", "model", "best.pt") + appBaseDir := exeDir + if strings.TrimSpace(appBaseDir) == "" { + appBaseDir, _ = os.Getwd() + } + + trainingRoot := filepath.Join(appBaseDir, "generated", "training") + detectionLabelsPath := filepath.Join(trainingRoot, "detection_labels.json") + defaultModelPath := filepath.Join(trainingRoot, "detector", "model", "best.pt") pythonPath := aiServerPythonPath() port := aiServerPortFromURL() @@ -328,14 +334,29 @@ func startAIServer(ctx context.Context) (*aiServerProcess, error) { "AI_SERVER_URL="+aiServerURL(), ) - // Defaults nur setzen, wenn nicht schon extern gesetzt. + // Immer App-Root/generated/training verwenden. + env = upsertEnv(env, "APP_BASE_DIR", appBaseDir) + env = upsertEnv(env, "TRAINING_ROOT", trainingRoot) + env = upsertEnv(env, "DETECTION_LABELS_PATH", detectionLabelsPath) + + // Modell ebenfalls standardmäßig aus generated/training nehmen, + // aber YOLO_MODEL darf weiterhin extern überschrieben werden. if strings.TrimSpace(os.Getenv("YOLO_MODEL")) == "" { - if fi, err := os.Stat(scriptDirModel); err == nil && fi != nil && !fi.IsDir() { - env = append(env, "YOLO_MODEL="+scriptDirModel) - } else if fi, err := os.Stat(defaultProdModel); err == nil && fi != nil && !fi.IsDir() { - env = append(env, "YOLO_MODEL="+defaultProdModel) - } + env = upsertEnv(env, "YOLO_MODEL", defaultModelPath) } + + if fi, err := os.Stat(detectionLabelsPath); err != nil || fi == nil || fi.IsDir() { + appLogln("⚠️ detection_labels.json nicht gefunden:", detectionLabelsPath) + } else { + appLogln("✅ detection_labels.json:", detectionLabelsPath) + } + + if fi, err := os.Stat(defaultModelPath); err != nil || fi == nil || fi.IsDir() { + appLogln("⚠️ YOLO Modell nicht gefunden:", defaultModelPath) + } else { + appLogln("✅ YOLO Modell:", defaultModelPath) + } + if strings.TrimSpace(os.Getenv("YOLO_IMGSZ")) == "" { env = append(env, "YOLO_IMGSZ=640") } @@ -415,6 +436,37 @@ func setEnvIfMissing(key, value string) { _ = os.Setenv(key, value) } +func upsertEnv(env []string, key string, value string) []string { + key = strings.TrimSpace(key) + value = strings.TrimSpace(value) + + if key == "" { + return env + } + + prefix := strings.ToUpper(key) + "=" + out := make([]string, 0, len(env)+1) + replaced := false + + for _, item := range env { + if strings.HasPrefix(strings.ToUpper(item), prefix) { + if !replaced && value != "" { + out = append(out, key+"="+value) + replaced = true + } + continue + } + + out = append(out, item) + } + + if !replaced && value != "" { + out = append(out, key+"="+value) + } + + return out +} + func loadEmbeddedDotEnv() { b, err := embeddedDotEnvBytes() if err != nil {