fixed training root detection

This commit is contained in:
Linrador 2026-05-12 10:00:59 +02:00
parent a59239bd36
commit a0489a63bb
3 changed files with 65 additions and 29 deletions

View File

@ -69,27 +69,11 @@ def resolve_detection_labels_path() -> Path:
return p return p
raise RuntimeError(f"DETECTION_LABELS_PATH not found: {p}") raise RuntimeError(f"DETECTION_LABELS_PATH not found: {p}")
candidates = [ p = TRAINING_ROOT / "detection_labels.json"
TRAINING_ROOT / "detection_labels.json", if existing_file(p):
return p.resolve()
# Wenn ai_server.py direkt neben detection_labels.json embedded liegt: raise RuntimeError(f"detection_labels.json not found: {p}")
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)
)
def resolve_model_path() -> str: def resolve_model_path() -> str:

View File

@ -63,7 +63,7 @@ const (
// Video-Modus: extrahiert 1 Frame alle N Sekunden. // Video-Modus: extrahiert 1 Frame alle N Sekunden.
// 1 = jeder Sekunde, 3 = alle 3 Sekunden, 5 = alle 5 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. // AI-Server nicht mit tausenden Pfaden auf einmal fluten.
analyzeFramePredictBatchSize = 32 analyzeFramePredictBatchSize = 32

View File

@ -298,8 +298,14 @@ func startAIServer(ctx context.Context) (*aiServerProcess, error) {
exeDir = filepath.Dir(exePath) exeDir = filepath.Dir(exePath)
} }
defaultProdModel := filepath.Join(exeDir, "generated", "training", "detector", "model", "best.pt") appBaseDir := exeDir
scriptDirModel := filepath.Join(scriptDir, "generated", "training", "detector", "model", "best.pt") 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() pythonPath := aiServerPythonPath()
port := aiServerPortFromURL() port := aiServerPortFromURL()
@ -328,14 +334,29 @@ func startAIServer(ctx context.Context) (*aiServerProcess, error) {
"AI_SERVER_URL="+aiServerURL(), "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 strings.TrimSpace(os.Getenv("YOLO_MODEL")) == "" {
if fi, err := os.Stat(scriptDirModel); err == nil && fi != nil && !fi.IsDir() { env = upsertEnv(env, "YOLO_MODEL", defaultModelPath)
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)
}
} }
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")) == "" { if strings.TrimSpace(os.Getenv("YOLO_IMGSZ")) == "" {
env = append(env, "YOLO_IMGSZ=640") env = append(env, "YOLO_IMGSZ=640")
} }
@ -415,6 +436,37 @@ func setEnvIfMissing(key, value string) {
_ = os.Setenv(key, value) _ = 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() { func loadEmbeddedDotEnv() {
b, err := embeddedDotEnvBytes() b, err := embeddedDotEnvBytes()
if err != nil { if err != nil {