Files
Home_assistant/backend/backfill_fitness_activity.py
T
2026-06-13 20:20:56 +00:00

73 lines
2.3 KiB
Python

"""Backfill workout active_calories / steps from notes via regex."""
from __future__ import annotations
import re
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from sqlalchemy import select
from app.db.base import SessionLocal
from app.db.models import WorkoutLog
ACTIVE_PATTERNS = [
re.compile(r"(?:active|активн(?:ые|ых)?)\s*(?:калор|kcal|ккал)[^\d]*(\d+(?:[.,]\d+)?)", re.I),
re.compile(r"(\d+(?:[.,]\d+)?)\s*(?:ккал|kcal)\s*(?:active|актив)", re.I),
re.compile(r"актив[^\d]{0,20}(\d+(?:[.,]\d+)?)", re.I),
]
TOTAL_PATTERNS = [
re.compile(r"(?:total|всего|сожжено|burned)[^\d]*(\d+(?:[.,]\d+)?)\s*(?:ккал|kcal)", re.I),
re.compile(r"(\d+(?:[.,]\d+)?)\s*(?:ккал|kcal)\s*(?:total|всего)", re.I),
]
STEPS_PATTERNS = [
re.compile(r"(?:шаг|step)s?\s*[:\-]?\s*(\d+)", re.I),
re.compile(r"(\d+)\s*(?:шаг|steps)", re.I),
]
def _first(patterns: list[re.Pattern[str]], text: str, *, as_int: bool = False):
for pat in patterns:
m = pat.search(text)
if not m:
continue
raw = m.group(1).replace(",", ".")
return int(float(raw)) if as_int else float(raw)
return None
def main() -> None:
db = SessionLocal()
updated = 0
try:
rows = db.scalars(select(WorkoutLog)).all()
for row in rows:
text = f"{row.title or ''}\n{row.notes or ''}"
changed = False
if row.active_calories is None:
val = _first(ACTIVE_PATTERNS, text)
if val is not None:
row.active_calories = float(val)
changed = True
if row.total_calories is None:
val = _first(TOTAL_PATTERNS, text)
if val is not None:
row.total_calories = float(val)
changed = True
if row.steps is None:
val = _first(STEPS_PATTERNS, text, as_int=True)
if val is not None:
row.steps = int(val)
changed = True
if changed:
updated += 1
db.commit()
print(f"updated {updated} workout rows")
finally:
db.close()
if __name__ == "__main__":
main()