/
Adnery
/
F4_BolideTracker
Обзор
Документация
Войти
/
Adnery
/
F4_BolideTracker
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
server.py
87 строк
4 KB
Andrey Maslov
fix: положение болида относительно кромок на карте (режимы 1/2)
15 июн 2026, 11:20
15 июн 2026, 11:20
808b292
Код
Авторство
О чём код?
"""Лёгкий бэкенд BolideTracker: отдаёт статику apex/ И обрабатывает видео на машине. Зачем: режим «только видео» считает траекторию тяжёлым ML-пайплайном (сегментация DeepLab + OCR HUD), что неподъёмно в браузере. Браузер загружает видео сюда → сервер прогоняет segmentation/build_video_track.py (быстро, на MPS) → возвращает video_track.json → фронт рисует. Модель грузится ОДИН раз при старте (тёплая) и переиспользуется между запросами. Запуск: ../.venv/bin/python server.py (порт 8753) открыть http://localhost:8753/apex/index.html Статика работает и без обработки; /api/video-track доступен только при запущенном сервере. """ import os, sys, tempfile, traceback from flask import Flask, request, jsonify, send_from_directory, redirect HERE = os.path.dirname(os.path.abspath(__file__)) APEX = os.path.join(HERE, "apex") SEG = os.path.join(HERE, "segmentation") # обучение + инференс сегментации (в репо) sys.path.insert(0, SEG) import torch from build_video_track import extract, build, load_model from track_map import TrackMap CKPT = os.path.join(SEG, "weights", "deeplabv3plus_r50_best.pth") DEVICE = "mps" if torch.backends.mps.is_available() else "cpu" _MODEL = None def model(): global _MODEL if _MODEL is None: print(f"[server] загрузка модели сегментации на {DEVICE}…") _MODEL, _ = load_model(CKPT, DEVICE) print("[server] модель готова") return _MODEL # статика — весь корень BolideTracker (как `http.server` из этой папки): нужно и apex/, # и studio/core/* (их импортирует Web Worker телеметрии через ../../studio/core/...) app = Flask(__name__, static_folder=HERE, static_url_path="") @app.route("/") def root(): return redirect("/apex/index.html") @app.route("/apex/api/video-track", methods=["POST"]) def video_track(): """multipart: video (файл) + track (имя карты, напр. moscow-gp). Возвращает video_track.json.""" try: track = request.form.get("track", "moscow-gp") stride = int(request.form.get("stride", 4)) f = request.files.get("video") if f is None: return jsonify({"error": "нет файла video"}), 400 map_path = os.path.join(APEX, "tracks", track + ".json") if not os.path.exists(map_path): return jsonify({"error": f"нет карты {track}"}), 400 tmp = tempfile.NamedTemporaryFile(suffix=os.path.splitext(f.filename or ".mp4")[1] or ".mp4", delete=False) f.save(tmp.name); tmp.close() try: tm = TrackMap.load(map_path) lat, fidx, fps, duration, rt, lapn, lt = extract( tmp.name, CKPT, 896, 512, stride, 0, 3, model=model(), device=DEVICE) frames, laps = build(lat, fidx, fps, tm, rt, lapn, lt, 7) on_pct = round(100.0 * sum(fr["onTrack"] for fr in frames) / max(1, len(frames)), 1) out = {"track": track, "fps": fps, "durationSec": round(duration, 2), "lapLengthM": round(tm.length, 1), "frames": frames, "metrics": {"frames": len(frames), "onTrackPct": on_pct, "laps": laps}} print(f"[server] {track}: {len(frames)} кадров, круги {laps}") return jsonify(out) finally: os.unlink(tmp.name) except Exception as e: traceback.print_exc() return jsonify({"error": str(e)}), 500 if __name__ == "__main__": model() # прогреть до первого запроса host = os.environ.get("HOST", "127.0.0.1") # на сервере задать HOST=0.0.0.0 port = int(os.environ.get("PORT", "8753")) print(f"[server] http://{host}:{port}/apex/index.html") app.run(host=host, port=port, threaded=True)