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
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:

View File

@ -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

View File

@ -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 {