diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..526d990 --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +# PostgreSQL Database Configuration +POSTGRES_DATABASE_DB=your_database_name +POSTGRES_DATABASE_USER=your_username +POSTGRES_DATABASE_PASSWORD=your_secure_password +POSTGRES_DATABASE_HOST=postgres +POSTGRES_DATABASE_PORT=5432 + +# FastAPI Configuration +PYTHONPATH=/app + +# Development settings +DEBUG=true diff --git a/.gitignore b/.gitignore index c340b9d..01f4c65 100644 --- a/.gitignore +++ b/.gitignore @@ -123,11 +123,14 @@ celerybeat.pid *.sage.py # Environments -.env .venv env/ venv/ ENV/ +.env +.env.local +.env.production + env.bak/ venv.bak/ @@ -163,3 +166,7 @@ cython_debug/ #.idea/ pyrightconfig.json + +# Database +*.db +*.sqlite3 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..737d084 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,86 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +F1tness Parser is a FastAPI-based web application that parses fitness training data from two note formats: +- **Obsidian Notes**: Markdown tables with `# DD.MM.YYYY (trainer-session)` headers +- **Apple Notes**: Bold markdown tables with `**DD.MM.YYYY (trainer-session)**` headers + +The application uses a layered architecture with parsers, models, services, and API endpoints. + +## Development Commands + +### Local Development +```bash +# Start development server +python run.py + +# Start with Docker Compose (includes PostgreSQL) +docker compose up --build + +# Run migrations manually +python -c "from migrations.runner import MigrationRunner; from app.config import settings; import asyncio; asyncio.run(MigrationRunner(settings.get_postgres_database_url()).run_migrations())" +``` + +### Testing +```bash +# Run tests +pytest + +# Run specific test file +pytest tests/test_core/test_obsidian_parser.py + +# Run tests with coverage +pytest --cov=app +``` + +### Type Checking +```bash +# Run type checking +mypy app/ +``` + +## Architecture + +### Core Components + +**Parser Architecture**: The system uses a base parser class (`app/core/parsers/base.py`) with format-specific implementations: +- `ObsidianNotesParser` - handles Obsidian markdown format +- `AppleNotesParser` - handles Apple notes format +- Each parser includes exercise name mapping for normalization + +**Data Models**: Located in `app/core/dto/training.py`: +- `Training` - represents a workout session +- `Exercise` - individual exercise with multiple approaches +- `Approach` - single set with weight and reps + +**API Structure**: +- `/api/v1/` - REST API endpoints +- `/app/` - Web interface endpoints +- Static files served from `app/static/` +- Templates in `app/templates/` + +### Database + +The application supports both SQLite (default) and PostgreSQL. Database migrations are handled by a custom migration runner in `migrations/runner.py` that reads SQL files from `migrations/sql/`. + +Configuration is managed through `app/config.py` using Pydantic settings with `.env` file support. + +### Key Files + +- `app/main.py` - FastAPI application setup with lifespan management +- `app/config.py` - Application configuration and database settings +- `run.py` - Development server entry point +- `migrations/runner.py` - Custom database migration system +- `compose.yaml` - Docker Compose setup with PostgreSQL + +## Environment Setup + +Copy `.env.example` to `.env` and configure: +- PostgreSQL connection settings +- Debug mode +- PYTHONPATH (for Docker) + +The application will run database migrations automatically on startup through the FastAPI lifespan event. diff --git a/DOCS/database_scheme.wsd b/DOCS/database_scheme.wsd index 053e886..dfe3745 100644 --- a/DOCS/database_scheme.wsd +++ b/DOCS/database_scheme.wsd @@ -19,6 +19,7 @@ $table("EXERCISE", "exercise"){ $column("NAME") VARCHAR } + $table("APPROACH", "approach"){ $pk("ID") INTEGER NOT NULL $fk("EXERCISE") INTEGER NOT NULL diff --git a/DOCS/deployment.puml b/DOCS/deployment.puml new file mode 100644 index 0000000..13008f2 --- /dev/null +++ b/DOCS/deployment.puml @@ -0,0 +1,25 @@ +@startuml +actor client +agent "web interface" as WEB_UI +agent "ios app" as IOS_APP +agent "telegram app" as TG_APP + +frame docker:f1tness_db { + database "PostgreSQL" as db +} + +frame docker:fastAPI { + node backend_API + node frontend_renderer +} + +client <--> WEB_UI +client <--> IOS_APP +client <--> TG_APP + +WEB_UI <--> frontend_renderer +IOS_APP <--> backend_API +TG_APP <--> backend_API + +backend_API --> db +@enduml \ No newline at end of file diff --git a/app/api/v1/endpoints/trainings.py b/app/api/v1/endpoints/trainings.py index 4c3d7b6..07b8d79 100644 --- a/app/api/v1/endpoints/trainings.py +++ b/app/api/v1/endpoints/trainings.py @@ -1,11 +1,62 @@ +from datetime import datetime +import logging from fastapi import APIRouter +from app.core.database.connection import SQLiteExecutor +from app.core.database.models.approach import ApproachOps +from app.core.database.models.training import TrainingOps +from app.core.database.models.exercise import ExerciseOps +from app.core.dto.training import TrainingDTO from app.core.parsers.obsidian import parse_training_data + +sqllite_executor = SQLiteExecutor() + router = APIRouter() + @router.get("/obsidian/") async def obsidian_trainings_list(): - return { - "data": parse_training_data() - } + return {"data": parse_training_data()} + + +@router.get("/test/create/") +async def create_sample_training(): + test_training = TrainingDTO(date=datetime.now().date(), trainer="Stepka") + training_executor = TrainingOps(sqllite_executor) + result_id = await training_executor.create(test_training) + return {"status": "ok", "create_id": result_id} + + +@router.get("/test/get/list/") +async def get_trainings_list(): + training_executor = TrainingOps(sqllite_executor) + results = await training_executor.list() + return {"status": "ok", "create_id": results} + + +@router.delete("/test/delete/") +async def delete_by_ids(): + training_executor = TrainingOps(sqllite_executor) + await training_executor.delete(list_of_ids=[4,5,6]) + return {"status": "ok"} + + +@router.post("/test/create/") +async def create_full_training(): + training_executor = TrainingOps(sqllite_executor) + exercise_executor = ExerciseOps(sqllite_executor) + approach_executor = ApproachOps(sqllite_executor) + sample_training_data: TrainingDTO = parse_training_data()[-1] + logging.info(sample_training_data) + training_id: int = await training_executor.create(sample_training_data) + if sample_training_data.exercises: + for exercise in sample_training_data.exercises: + exercise.training_id = training_id + exercise_id: int = await exercise_executor.create(exercise) + if exercise.approaches: + for approach in exercise.approaches: + approach.exercise_id = exercise_id + await approach_executor.create(approach) + + return {"status": "ok"} diff --git a/app/config.py b/app/config.py index 79864a8..7e2f71c 100644 --- a/app/config.py +++ b/app/config.py @@ -1,14 +1,38 @@ -from pydantic_settings import BaseSettings +from pydantic_settings import BaseSettings, SettingsConfigDict from typing import Optional class Settings(BaseSettings): - app_name: str = "Fitness Parser API" - version: str = "0.1.0" + # Base app settings + model_config = SettingsConfigDict(env_file=".env") + app_name: str = "F1tness Parser API" + version: str = "0.0.1" debug: bool = False - - class Config: - env_file = ".env" + + # SQLite database settings + SQLITE_DATABASE_PATH: str = "fitness.db" + + # Postgres database settings + POSTGRES_DATABASE_URL: Optional[str] = None + POSTGRES_DATABASE_HOST: str = "localhost" + POSTGRES_DATABASE_PORT: int = 5432 + POSTGRES_DATABASE_DB: str = "f1tness_db" + POSTGRES_DATABASE_USER: str = "postgres" + POSTGRES_DATABASE_PASSWORD: str = "password" + + def get_postgres_database_url(self, async_driver: bool = True) -> str: + """Method for receiving relational database URL""" + + # If POSTGRES_DATABASE_URL is somehow set in env file - return it + if self.POSTGRES_DATABASE_URL: + return self.POSTGRES_DATABASE_URL + + driver = "postgresql+asyncpg" if async_driver else "postgresql" + return ( + f"{driver}://{self.POSTGRES_DATABASE_USER}:{self.POSTGRES_DATABASE_PASSWORD}" + f"@{self.POSTGRES_DATABASE_HOST}" + f":{self.POSTGRES_DATABASE_PORT}/{self.POSTGRES_DATABASE_DB}" + ) -settings = Settings() \ No newline at end of file +settings = Settings() diff --git a/app/core/models/__init__.py b/app/core/database/__init__.py similarity index 100% rename from app/core/models/__init__.py rename to app/core/database/__init__.py diff --git a/app/core/database/connection.py b/app/core/database/connection.py new file mode 100644 index 0000000..97d508a --- /dev/null +++ b/app/core/database/connection.py @@ -0,0 +1,36 @@ +from typing import Dict, List, Any +import aiosqlite +from app.config import settings + + +class SQLiteExecutor: + """Executor для SQL запросов в БД SQLlite""" + def __init__(self) -> None: + self._db_path = settings.SQLITE_DATABASE_PATH + + async def execute_query( + self, query: str, params: tuple = () + ) -> List[Dict[str, Any]]: + """Выполнить запрос, который не должен вносить изменения в БД. + + :param query: SQL запрос + :param params: Параметры, которые нужно передать вместе с запросом + :return: Список, выдаваемый aiosqlite + """ + async with aiosqlite.connect(self._db_path) as db: + db.row_factory = aiosqlite.Row + cursor = await db.execute(query, params) + rows = await cursor.fetchall() + return [dict(row) for row in rows] + + async def execute_mod_query(self, query: str, params: tuple = ()) -> int: + """Выполнить запрос, который что-то изменяет в БД. + + :param query: SQL запрос + :param params: Параметры, которые нужно передать вместе с запросом + :return: Список, выдаваемый aiosqlite + """ + async with aiosqlite.connect(self._db_path) as db: + cursor = await db.execute(query, params) + await db.commit() + return cursor.lastrowid if cursor.lastrowid else cursor.rowcount diff --git a/app/core/database/models/__init__.py b/app/core/database/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/core/database/models/approach.py b/app/core/database/models/approach.py new file mode 100644 index 0000000..3cfcb19 --- /dev/null +++ b/app/core/database/models/approach.py @@ -0,0 +1,26 @@ +from typing import List, Dict, Any +from app.core.database.connection import SQLiteExecutor +from app.core.dto.training import ApproachDTO + + +class ApproachOps: + TABLE_NAME: str = "approaches" + + def __init__(self, executor: SQLiteExecutor) -> None: + self._executor = executor + + async def create(self, approach: ApproachDTO) -> int: + query = f"INSERT INTO {self.TABLE_NAME} (exercise_id, weight, reps) VALUES (?, ?, ?)" + return await self._executor.execute_mod_query( + query, (approach.exercise_id, approach.weight, approach.reps) + ) + + async def list(self) -> List[Dict[str, Any]]: + query = f"SELECT * FROM {self.TABLE_NAME}" + return await self._executor.execute_query(query) + + async def delete(self, list_of_ids: List[int]) -> None: + placeholders: str = ",".join("?" * len(list_of_ids)) + query = f"DELETE FROM {self.TABLE_NAME} WHERE id IN ({placeholders})" + await self._executor.execute_mod_query(query, tuple(list_of_ids)) + return None diff --git a/app/core/database/models/exercise.py b/app/core/database/models/exercise.py new file mode 100644 index 0000000..a453799 --- /dev/null +++ b/app/core/database/models/exercise.py @@ -0,0 +1,26 @@ +from typing import List, Dict, Any +from app.core.database.connection import SQLiteExecutor +from app.core.dto.training import ExerciseDTO + + +class ExerciseOps: + TABLE_NAME: str = "exercises" + + def __init__(self, executor: SQLiteExecutor) -> None: + self._executor = executor + + async def create(self, exercise: ExerciseDTO) -> int: + query = f"INSERT INTO {self.TABLE_NAME} (training_id, name, splitted_weight) VALUES (?, ?, ?)" + return await self._executor.execute_mod_query( + query, (exercise.training_id, exercise.name, exercise.splitted_weight) + ) + + async def list(self) -> List[Dict[str, Any]]: + query = f"SELECT * FROM {self.TABLE_NAME}" + return await self._executor.execute_query(query) + + async def delete(self, list_of_ids: List[int]) -> None: + placeholders: str = ",".join("?" * len(list_of_ids)) + query = f"DELETE FROM {self.TABLE_NAME} WHERE id IN ({placeholders})" + await self._executor.execute_mod_query(query, tuple(list_of_ids)) + return None diff --git a/app/core/database/models/training.py b/app/core/database/models/training.py new file mode 100644 index 0000000..5ea30c3 --- /dev/null +++ b/app/core/database/models/training.py @@ -0,0 +1,26 @@ +from typing import List, Dict, Any +from app.core.database.connection import SQLiteExecutor +from app.core.dto.training import TrainingDTO + + +class TrainingOps: + TABLE_NAME: str = "trainings" + + def __init__(self, executor: SQLiteExecutor) -> None: + self._executor = executor + + async def create(self, training: TrainingDTO) -> int: + query = f"INSERT INTO {self.TABLE_NAME} (date, trainer) VALUES (?, ?)" + return await self._executor.execute_mod_query( + query, (training.date, training.trainer) + ) + + async def list(self) -> List[Dict[str, Any]]: + query = f"SELECT * FROM {self.TABLE_NAME}" + return await self._executor.execute_query(query) + + async def delete(self, list_of_ids: List[int]) -> None: + placeholders: str = ",".join("?" * len(list_of_ids)) + query = f"DELETE FROM {self.TABLE_NAME} WHERE id IN ({placeholders})" + await self._executor.execute_mod_query(query, tuple(list_of_ids)) + return None diff --git a/app/core/dto/__init__.py b/app/core/dto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/core/dto/training.py b/app/core/dto/training.py new file mode 100644 index 0000000..c853add --- /dev/null +++ b/app/core/dto/training.py @@ -0,0 +1,25 @@ +from typing import List, Optional +from pydantic import BaseModel +from datetime import date + + +class ApproachDTO(BaseModel): + id: Optional[int] = None + exercise_id: Optional[int] = None + weight: float + reps: int + + +class ExerciseDTO(BaseModel): + id: Optional[int] = None + training_id: Optional[int] = None + name: str + splitted_weight: bool = False + approaches: Optional[List[ApproachDTO]] = None + + +class TrainingDTO(BaseModel): + id: Optional[int] = None + date: date + trainer: Optional[str] = None + exercises: Optional[List[ExerciseDTO]] = None diff --git a/app/core/models/training.py b/app/core/models/training.py deleted file mode 100644 index d429b64..0000000 --- a/app/core/models/training.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import List, Optional -from pydantic import BaseModel -from datetime import date - - -class Approach(BaseModel): - weight: float - reps: int - - -class Exercise(BaseModel): - name: str - splitted_weight: bool = False - approaches: List[Approach] - - -class Training(BaseModel): - date: date - exercises: Optional[List[Exercise]] - - -class Coach(BaseModel): - name: str \ No newline at end of file diff --git a/app/core/parsers/apple.py b/app/core/parsers/apple.py index c655504..68b6acc 100644 --- a/app/core/parsers/apple.py +++ b/app/core/parsers/apple.py @@ -2,7 +2,7 @@ import re from typing import List, Tuple from datetime import datetime -from app.core.models.training import Training +from app.core.dto.training import TrainingDTO from app.core.parsers.apple_mapper import unique_apple_exercises_mapper from app.core.parsers.base import BaseNotesParser @@ -11,7 +11,7 @@ class AppleNotesParser(BaseNotesParser): """Parser for Apple Notes format training data.""" def __init__(self): - super().__init__("apple.md", unique_apple_exercises_mapper) + super().__init__("complete_data/apple.md", unique_apple_exercises_mapper) def filter_training_data(self, training_data: str) -> str: """Filter Apple-specific training data format.""" @@ -47,18 +47,18 @@ class AppleNotesParser(BaseNotesParser): return True, date, trainer, year_count return False, "", "", "" - def create_training_from_date(self, date_str: str) -> Training: + def create_training_from_date(self, date_str: str) -> TrainingDTO: """Create Training object from date string with fallback parsing.""" try: - return Training( + return TrainingDTO( date=datetime.strptime(date_str, "%d.%m.%Y").date(), exercises=[] ) except ValueError: - return Training( + return TrainingDTO( date=datetime.strptime(date_str, "%d.%m.%y").date(), exercises=[] ) - def parse(self, data: str) -> List[Training]: + def parse(self, data: str) -> List[TrainingDTO]: """Parse Apple Notes training data from string input.""" # Override the data file reading with direct string input original_method = self.read_data_file @@ -72,13 +72,13 @@ class AppleNotesParser(BaseNotesParser): self.read_data_file = original_method -def parse_training_data() -> List[Training]: +def parse_training_data() -> List[TrainingDTO]: """Parse Apple Notes training data.""" parser = AppleNotesParser() return parser.parse_training_data() -def remap_unique_exercises(apple_trainings: List[Training]) -> List[Training]: +def remap_unique_exercises(apple_trainings: List[TrainingDTO]) -> List[TrainingDTO]: """Remap exercise names using Apple-specific mapping (deprecated - use parser.parse_and_map_training_data()).""" parser = AppleNotesParser() - return parser.apply_exercise_mapping(apple_trainings) \ No newline at end of file + return parser.apply_exercise_mapping(apple_trainings) diff --git a/app/core/parsers/apple_mapper.py b/app/core/parsers/apple_mapper.py index 5fc35be..49bbdd3 100644 --- a/app/core/parsers/apple_mapper.py +++ b/app/core/parsers/apple_mapper.py @@ -1,9 +1,79 @@ +list_of_unique_apple_names = [ + "Тяга горизонтального блока", + "Тяга горизонтального блока (по очереди)", + "Тяга гантелей в наклоне (по очереди)", + "Тяга гантелей на скамье", + "Тяга вертикального блока", + "Тяга вертикального блока (обратный хват)", + "Разгибание рук сидя (трицепс машина)", + "Подъем штанги на бицепс стоя", + "Подъем гантелей на бицепс стоя", + "Сгибание ног сидя", + "Сгибание ног лежа", + "Сведение рук в пек-дек", + "Румынская тяга", + "Разгибание ног сидя", + "Махи гантелей стоя", + "Разведение рук в стороны в наклоне (гантели)", + "Приседания", + "Подъем ног на турнике", + "Подтягивания", + "Подтягивания обратным хватом", + "Отжимания", + "Отведение рук в кроссовере (по очереди)", + "Разведение рук в пек-дек (по очереди)", + "Разведение рук в пек-дек", + "Отжимание на трицепс в кроссовере", + "Баттерфляй", + "Болгарские сплит-приседания", + "Брусья", + "Вертикальная тяга одной рукой", + "Выпады", + "Гиперэкстензия", + "Гравитрон", + "Гребная тяга с упором в грудь (по очереди)", + "Разведение рук в стороны (дельт-машина)", + "Жим гантелей лежа", + "Жим гантелей лежа (Под углом 45 градусов)", + "Жим гантелей сидя", + "Жим ногами", + "Жим от груди сидя в тренажере (рычаги)", + "Жим от плеч вверх в тренажере (рычаги)", + "Икроножные сидя", + "Пресс на наклонной скамье", + "Бицепс машина", + "Pull down", + "Тяга Т-грифа", + "Французский жим гантели сидя", + "Молоты стоя (наискосок)", + "Отведение руки из-за спины в кроссовере", + "Гребная тяга с упором в грудь", + "Тяга штанги в наклоне", + "Молоты стоя", + "Жим штанги лежа", + "Тяга штанги в наклоне (обратным хватом)", + "Жим штанги сидя (45 градусов)", + "Наклоны с прямой спиной", + "Разгибание рук в наклоне (кик-бек)", + "Разгибание спины", + "Скручивания", + "Подъем гантелей на бицепс сидя" +] + + unique_apple_exercises_mapper = { + # Баттерфляй "Батерфляй": "Баттерфляй", "Баттерфляй": "Баттерфляй", "Баттерфляй дю": "Баттерфляй", + + # Подъем гантелей на бицепс сидя "Бицепс на лавке 45⁰": "Подъем гантелей на бицепс сидя", - "Болгарский присед": "Болгарские сплит-приседения", + + # Болгарские сплит-приседания + "Болгарский присед": "Болгарские сплит-приседания", + + # Брусья "Брусья": "Брусья", "Брусья (гравитрон)": "Брусья", "Брусья в тренажере": "Брусья", @@ -12,42 +82,48 @@ unique_apple_exercises_mapper = { "Брусья узким хватом за": "Брусья", "Брусья широким хватом": "Брусья", "Брусья-прямые ноги": "Брусья", - "ГАК машина": "Жим ногами (гакк-машина)", - "Гакк машина": "Жим ногами (гакк-машина)", - "Гакк присед": "Жим ногами (гакк-машина)", - "Гантели": "Подъем гантелей на бицепс стоя", - "Гантели к поясу лежа на скамье": "Тяга гантелей на скамье", - "Гантели молот": "Гантели молот", - "Гантели на лавках": "Жим гантелей сидя", - "Гантели-молот": "Гантели молот", + "Отжимания на брусьях": "Брусья", + "Отжимания на брусьях узким хватом": "Брусья", + "Отжимания на брусьях широким хватом": "Брусья", + + # Выпады + "Присд на одну ногу (по очереди)": "Выпады", + "Присед на одну ногу": "Выпады", + "Присед на одну ногу (каждая)": "Выпады", + "Приседания на одной ноге": "Выпады", + + # Молоты стоя + "Гантели молот": "Молоты стоя", + "Гантели-молот": "Молоты стоя", + "Молот назад двумя руками": "Молоты стоя", + "Молот трицепс стоя": "Молоты стоя", + "Молоты": "Молоты стоя", + "Сгибание гантелей в стиле молот одновременно": "Молоты стоя", + + # Гиперэкстензия "Гипекстензия": "Гиперэкстензия", "Гиперэкстензия": "Гиперэкстензия", - "Горизонтальна тяга на себя": "Тяга горизонтального блока", - "Горизонтальная тяга блока": "Тяга горизонтального блока", - "Гравитрон": "Гравитрон", + + # Гравитрон "Гравитрор": "Гравитрон", + + # Гребная тяга с упором в грудь "Гребная тяга": "Гребная тяга с упором в грудь", "Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь", "Гребная тяга с упором в грудь как": "Гребная тяга с упором в грудь", "Гребная тяга с упором на грудь": "Гребная тяга с упором в грудь", - "Гребная тяга сидя (одна рука)": "Гребная тяга с упором в грудь (по очереди)", - "Гребная тяга сидя одной рукой": "Гребная тяга с упором в грудь (по очереди)", "Гребная тяга сидя с упором в грудт": "Гребная тяга с упором в грудь", "Гребная тяга сидя с упором в грудь": "Гребная тяга с упором в грудь", - "Гребная тяга сидя с упором в грудь (одной рукой рычаг)": "Гребная тяга с упором в грудь (по очереди)", "Гребная тяга\xa0 упором в грудьс": "Гребная тяга с упором в грудь", - "Жим в тренажере вверх": "Жим от плеч вверх в тренажере (рычаги)", - "Жим в тренажере на плечи блочный (3х12)": "Жим от плеч вверх в тренажере (рычаги)", - "Жим в тренажёре на плечи (силовой тренажёр: жим сидя)": "Жим от плеч вверх в тренажере (рычаги)", - "Жим вверх 80⁰": "Жим гантелей сидя", + "Тяга на себя с упором в грудь": "Гребная тяга с упором в грудь", + + # Гребная тяга с упором в грудь (по очереди) + "Гребная тяга сидя (одна рука)": "Гребная тяга с упором в грудь (по очереди)", + "Гребная тяга сидя одной рукой": "Гребная тяга с упором в грудь (по очереди)", + "Гребная тяга сидя с упором в грудь (одной рукой рычаг)": "Гребная тяга с упором в грудь (по очереди)", + + # Жим гантелей лежа "Жим гантелей": "Жим гантелей лежа", - "Жим гантелей 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", - "Жим гантелей 60⁰": "Жим гантелей лежа (Под углом 45 градусов)", - "Жим гантелей 80⁰": "Жим гантелей сидя", - "Жим гантелей 90⁰": "Жим гантелей сидя", - "Жим гантелей вверх 80⁰": "Жим гантелей сидя", - "Жим гантелей вверх 90⁰": "Жим гантелей сидя", - "Жим гантелей вверх сидя 90⁰": "Жим гантелей сидя", "Жим гантелей лежа": "Жим гантелей лежа", "Жим гантелей лежа 15⁰": "Жим гантелей лежа", "Жим гантелей лежа 30⁰": "Жим гантелей лежа", @@ -55,37 +131,64 @@ unique_apple_exercises_mapper = { "Жим гантелей лёжа": "Жим гантелей лежа", "Жим гантелей лёжа на скамье": "Жим гантелей лежа", "Жим гантелей на скамье": "Жим гантелей лежа", + "Жис гантелей лежа": "Жим гантелей лежа", + + # Жим гантелей лежа (Под углом 45 градусов) + "Жим гантелей 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", + "Жим гантелей 60⁰": "Жим гантелей лежа (Под углом 45 градусов)", "Жим гантелей на скамье 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", + "Жим сидя 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", + + # Жим гантелей сидя + "Жим гантелей 80⁰": "Жим гантелей сидя", + "Жим гантелей 90⁰": "Жим гантелей сидя", + "Жим гантелей вверх 80⁰": "Жим гантелей сидя", + "Жим гантелей вверх 90⁰": "Жим гантелей сидя", + "Жим гантелей вверх сидя 90⁰": "Жим гантелей сидя", "Жим гантелей сидя": "Жим гантелей сидя", "Жим гантелей сидя 80⁰": "Жим гантелей сидя", "Жим гантелей сидя 90⁰": "Жим гантелей сидя", "Жим гантелей сидя на скамейке": "Жим гантелей сидя", - "Жим гантелей стоя": "Подъем гантелей на бицепс стоя", - "Жим л груди в тренажёре": "Жим от груди сидя в тренажере (рычаги)", - "Жим лежа": "Жим штанги лежа", + "Жим вверх 80⁰": "Жим гантелей сидя", + "Жим от плеч вверх сидя 80⁰": "Жим гантелей сидя", + "Гантели на лавках": "Жим гантелей сидя", + + # ГАК машина + "ГАК машина": "ГАК машина", + "Гакк машина": "ГАК машина", + "Гакк присед": "ГАК машина", + + # Жим ногами "Жим ногами": "Жим ногами", "Жим ногами (3х15)": "Жим ногами", "Жим ногами (медленно вниз)": "Жим ногами", "Жим ногами лежа": "Жим ногами", "Жим ногами медленно": "Жим ногами", - "Жим от груди": "Жим штанги лежа", - "Жим от груди (сидя, тренажёр)": "Жим от груди сидя в тренажере (блоки)", - "Жим от груди в тренажере сидя": "Жим от груди сидя в тренажере (блоки)", - "Жим от груди в тренажёре (кирпичики)": "Жим от груди сидя в тренажере (блоки)", - "Жим от груди сидя": "Жим от груди сидя в тренажере (блоки)", + + # Жим от груди сидя в тренажере (рычаги) + "Жим л груди в тренажёре": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя (блинчики)": "Жим от груди сидя в тренажере (рычаги)", - "Жим от груди сидя в тренажере": "Жим от груди сидя в тренажере (блоки)", - "Жим от груди сидя в тренажере (около трицепс машины)": "Жим от груди сидя в тренажере (блоки)", "Жим от груди сидя в тренажере (рычаги)": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя в тренажере рычаги": "Жим от груди сидя в тренажере (рычаги)", - "Жим от груди сидя в тренажёре": "Жим от груди сидя в тренажере (блоки)", - "Жим от груди сидя в тренажёре (блинчики)": "Жим от груди сидя в тренажере (блоки)", "Жим от груди сидя в тренажёре (рычаги)": "Жим от груди сидя в тренажере (рычаги)", + "Жис сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди (сидя, тренажёр)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди в тренажере сидя": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажере": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажере (около трицепс машины)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре (блинчики)": "Жим от груди сидя в тренажере (рычаги)", + "Силовой тренажер": "Жим от груди сидя в тренажере (рычаги)", + + # Жим от плеч вверх в тренажере (рычаги) + "Жим в тренажере вверх": "Жим от плеч вверх в тренажере (рычаги)", + "Жим в тренажере на плечи блочный (3х12)": "Жим от плеч вверх в тренажере (рычаги)", + "Жим в тренажёре на плечи (силовой тренажёр: жим сидя)": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч (рычаги)": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч вверх": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч вверх в тренажёре": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч вверх сидя": "Жим от плеч вверх в тренажере (рычаги)", - "Жим от плеч вверх сидя 80⁰": "Жим гантелей сидя", "Жим от плеч вверх сидя в тренажере": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч сидя": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч сидя (рычаги)": "Жим от плеч вверх в тренажере (рычаги)", @@ -93,32 +196,31 @@ unique_apple_exercises_mapper = { "Жим от плеч сидя хз": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плечей вверх": "Жим от плеч вверх в тренажере (рычаги)", "Жим плечами вверх сидя": "Жим от плеч вверх в тренажере (рычаги)", - "Жим сидя 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", - "Жим штанги 45⁰": "Жим штанги сидя (45 градусов)", - "Жим штанги в наклоне": "Тяга штанги в наклоне", + + # Жим штанги лежа + "Жим лежа": "Жим штанги лежа", + "Жим от груди": "Жим штанги лежа", "Жим штанги лежа": "Жим штанги лежа", + "Штанга": "Жим штанги лежа", + "Штанга лежа": "Жим штанги лежа", + + # Жим штанги сидя (45 градусов) + "Жим штанги 45⁰": "Жим штанги сидя (45 градусов)", "Жим штанги сидя 45⁰": "Жим штанги сидя (45 градусов)", - "Жим штанги стля": "Подъем штанги на бицепс стоя", - "Жим штанги стоя": "Подъем штанги на бицепс стоя", - "Жис гантелей лежа": "Жим гантелей лежа", - "Жис сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)", - "Махи в наклоне с упором": "Разведение рук в стороны в наклоне (гантели)", - "Молот назад двумя руками": "Гантели молот", - "Молот трицепс стоя": "Гантели молот", - "Молоты": "Гантели молот", - "Наклонная тяга (скамья)": "Жим штанги лежа", - "Наклоны с прямой спиной": "Наклоны с прямой спиной", + + # Махи гантелей стоя + "Отведение рук в стороны с гантелями стоя": "Махи гантелей стоя", + "Отведение рук в стороны стоя с гантелями": "Махи гантелей стоя", + "Отведение рук с гантелями стоя": "Махи гантелей стоя", + "Отведение рук стоя с гантелями": "Махи гантелей стоя", + "Разведение рук в стороны с гантелям": "Махи гантелей стоя", + "Разведение рук в стороны стоя": "Махи гантелей стоя", + "Разведение рук в стороны стоя с гантелями": "Махи гантелей стоя", + "Разведение рук стоя с гантелями": "Махи гантелей стоя", + "Разведение рук в стрроны": "Махи гантелей стоя", + + # Отведение рук в кроссовере (по очереди) "Отведение в кроссовере одной рукой": "Отведение рук в кроссовере (по очереди)", - "Отведение в рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", - "Отведение назад в пек дек": "Разведение рук в пек-дек", - "Отведение назад в тренажере пек дек": "Разведение рук в пек-дек", - "Отведение назад в тренажере пэк дэк (3х12)": "Разведение рук в пек-дек", - "Отведение рук в кроссовере": "Отведение рук в кроссовере (по очереди)", - "Отведение рук в стороны с гантелями стоя": "Разведение рук в стороны стоя (гантели)", - "Отведение рук в стороны стоя с гантелями": "Разведение рук в стороны стоя (гантели)", - "Отведение рук назад в пек дек": "Разведение рук в пек-дек", - "Отведение рук с гантелями стоя": "Разведение рук в стороны стоя (гантели)", - "Отведение рук стоя с гантелями": "Разведение рук в стороны стоя (гантели)", "Отведение руки в кроссовере": "Отведение рук в кроссовере (по очереди)", "Отведение руки в кроссовере (одной рукой)": "Отведение рук в кроссовере (по очереди)", "Отведение руки в кроссовере (по одной руке)": "Отведение рук в кроссовере (по очереди)", @@ -128,75 +230,107 @@ unique_apple_exercises_mapper = { "Отведение руки в сторону в кроссовере (каждая рука)": "Отведение рук в кроссовере (по очереди)", "Отведение руки стоя": "Отведение рук в кроссовере (по очереди)", "Отведение руки стоя снизу вверх": "Отведение рук в кроссовере (по очереди)", - "Отжимания": "Отжимания", - "Отжимания на брусьях": "Брусья", - "Отжимания на брусьях узким хватом": "Брусья", - "Отжимания на брусьях широким хватом": "Брусья", - "Пек дек (отведение назад)": "Разведение рук в пек-дек", - "Пек дек разведение рук в стороны": "Разведение рук в пек-дек", + + # Отжимание на трицепс в кроссовере + "Разведение рук в кроссовере на трицепс": "Отжимание на трицепс в кроссовере", + "Разгибание рук в кроссовере": "Отжимание на трицепс в кроссовере", + "Разгибание рук в тренажёре для трицепса": "Отжимание на трицепс в кроссовере", + "Разгибание рук в трицепс машине (3х10)": "Отжимание на трицепс в кроссовере", + "Разгибание рук стоя с канатом": "Отжимание на трицепс в кроссовере", + "Трацепс": "Отжимание на трицепс в кроссовере", + "Трицепс вниз у стойки": "Отжимание на трицепс в кроссовере", + + # Подтягивания "Подтягивание на заднюю дельту в петлях": "Подтягивания", - "Подтягивание ног на ручнике": "Подъем ног на турнике", - "Подтягивание ног на турнике": "Подъем ног на турнике", - "Подтягивание ног прямых вися на турнике": "Подъем ног на турнике", "Подтягивания": "Подтягивания", "Подтягивания в гравитроне": "Подтягивания", "Подтягивания на резинке": "Подтягивания", - "Подтягивания обратным хватом": "Подтягивания обратным хватом", "Подтяотвания": "Подтягивания", - "Подъем коленей на турнике": "Подъем ног на турнике", - "Подъем ног на турнике": "Подъем ног на турнике", - "Подъем штанги стоя": "Подъем штанги на бицепс стоя", - "Подъёмы ног на турнике": "Подъем ног на турнике", - "Подьем штанги стоя": "Подъем штанги на бицепс стоя", - "Присд на одну ногу (по очереди)": "Выпады", - "Присед на одну ногу": "Выпады", - "Присед на одну ногу (каждая)": "Выпады", - "Приседания": "Приседания", - "Приседания на одной ноге": "Выпады", - "Разведение рук в кроссовере на трицепс": "Отжимание на трицепс в кроссовере", - "Разведение рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", - "Разведение рук в налоне": "Разведение рук в стороны в наклоне (гантели)", + + # Подтягивания обратным хватом + "Подтягивания обратным хватом": "Подтягивания обратным хватом", + + # Подъем гантелей на бицепс стоя + "Гантели": "Подъем гантелей на бицепс стоя", + "Жим гантелей стоя": "Подъем гантелей на бицепс стоя", + "Сгибание рук с гантелями стоя": "Подъем гантелей на бицепс стоя", + "Сгибание рук с гантелями стоя ям": "Подъем гантелей на бицепс стоя", + + # Подъём ног в висе + "Подтягивание ног на ручнике": "Подъём ног в висе", + "Подтягивание ног на турнике": "Подъём ног в висе", + "Подтягивание ног прямых вися на турнике": "Подъём ног в висе", + "Подъем коленей на турнике": "Подъём ног в висе", + "Подъем ног на турнике": "Подъём ног в висе", + "Подъёмы ног на турнике": "Подъём ног в висе", + + # Подъем штанги стоя + "Жим штанги стля": "Подъем штанги стоя", + "Жим штанги стоя": "Подъем штанги стоя", + "Подьем штанги стоя": "Подъем штанги стоя", + "Сгибание со штангой стоя (3х12)": "Подъем штанги стоя", + "Сгибания рук со штангой стоя": "Подъем штанги стоя", + "Тяга штанги стоя": "Подъем штанги стоя", + "Штанга стоя": "Подъем штанги стоя", + + # Разведение рук в пек-дек + "Отведение назад в пек дек": "Разведение рук в пек-дек", + "Отведение назад в тренажере пек дек": "Разведение рук в пек-дек", + "Отведение назад в тренажере пэк дэк (3х12)": "Разведение рук в пек-дек", + "Отведение рук назад в пек дек": "Разведение рук в пек-дек", + "Пек дек (отведение назад)": "Разведение рук в пек-дек", + "Пек дек разведение рук в стороны": "Разведение рук в пек-дек", "Разведение рук в пек дек": "Разведение рук в пек-дек", "Разведение рук в стороны": "Разведение рук в пек-дек", - "Разведение рук в стороны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны (дельта-машина)": "Разведение рук в стороны (дельт-машина)", "Разведение рук в стороны (пек дек)": "Разведение рук в пек-дек", - "Разведение рук в стороны в наклоне 90⁰": "Разведение рук в стороны в наклоне (гантели)", - "Разведение рук в стороны в наклоне с гантелями": "Разведение рук в стороны в наклоне (гантели)", "Разведение рук в стороны в пекдек": "Разведение рук в пек-дек", "Разведение рук в стороны в тренажёре": "Разведение рук в пек-дек", "Разведение рук в стороны в тренажёре Дж": "Разведение рук в пек-дек", "Разведение рук в стороны пек дек": "Разведение рук в пек-дек", - "Разведение рук в стороны с гантелям": "Разведение рук в стороны стоя (гантели)", - "Разведение рук в стороны стоя": "Разведение рук в стороны стоя (гантели)", - "Разведение рук в стороны стоя с гантелями": "Разведение рук в стороны стоя (гантели)", - "Разведение рук в стрроны": "Разведение рук в стороны стоя (гантели)", "Разведение рук назад в пек дек": "Разведение рук в пек-дек", "Разведение рук назад пек дек": "Разведение рук в пек-дек", "Разведение рук пек дек": "Разведение рук в пек-дек", "Разведение рук сидя": "Разведение рук в пек-дек", "Разведение рук сидя с прямыми руками в тренажере": "Разведение рук в пек-дек", - "Разведение рук стоя с гантелями": "Разведение рук в стороны стоя (гантели)", - "Разгибание из за головы": "Гантели молот", - "Разгибание кик-бек": "Разгибание рук в наклоне (кик-бек)", + + # Разведение рук в стороны (дельт-машина) + "Разведение рук в стороны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны (дельта-машина)": "Разведение рук в стороны (дельт-машина)", + "Разгибание прямых рук сидя": "Разведение рук в стороны (дельт-машина)", + + # Разведение рук в стороны в наклоне (гантели) + "Махи в наклоне с упором": "Разведение рук в стороны в наклоне (гантели)", + "Отведение в рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в налоне": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в стороны в наклоне 90⁰": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в стороны в наклоне с гантелями": "Разведение рук в стороны в наклоне (гантели)", "Разгибание локтей в наклоне": "Разведение рук в стороны в наклоне (гантели)", + "Сведение на скамейке": "Разведение рук в стороны в наклоне (гантели)", + + # Разгибание ног сидя "Разгибание ног": "Разгибание ног сидя", "Разгибание ног сидя": "Разгибание ног сидя", "Разгибание ног сидя (4х10)": "Разгибание ног сидя", - "Разгибание прямых рук сидя": "Разведение рук в стороны (дельт-машина)", - "Разгибание рук в кроссовере": "Отжимание на трицепс в кроссовере", - "Разгибание рук в тренажёре для трицепса": "Отжимание на трицепс в кроссовере", - "Разгибание рук в трицепс машине (3х10)": "Отжимание на трицепс в кроссовере", + + # Разгибание рук в наклоне (кик-бек) + "Разгибание кик-бек": "Разгибание рук в наклоне (кик-бек)", + + # Разгибание рук сидя (трицепс машина) "Разгибание рук сидя": "Разгибание рук сидя (трицепс машина)", "Разгибание рук сидя (локти в стороны)": "Разгибание рук сидя (трицепс машина)", "Разгибание рук сидя (трицепс машина)": "Разгибание рук сидя (трицепс машина)", - "Разгибание рук стоя с канатом": "Отжимание на трицепс в кроссовере", - "Разгибание спины": "Разгибание спины", + "Трицепс машина": "Разгибание рук сидя (трицепс машина)", + "Трицепс сидя": "Разгибание рук сидя (трицепс машина)", + "Трицепс-машина (разгибание рук сидя)": "Разгибание рук сидя (трицепс машина)", + + # Румынская тяга "Румынская тяга": "Румынская тяга", "Румынская тяга с гантелями": "Румынская тяга", "Румынская тяна": "Румынская тяга", "Румынская тяоа": "Румынская тяга", - "Сведение на скамейке":"Разведение рук в стороны в наклоне (гантели)", + + # Сведение рук в пек-дек "Сведение рук в пек дек": "Сведение рук в пек-дек", "Сведение рук в пек дек зэ": "Сведение рук в пек-дек", "Сведение рук в тренажере": "Сведение рук в пек-дек", @@ -206,37 +340,39 @@ unique_apple_exercises_mapper = { "Сведение рук сидя": "Сведение рук в пек-дек", "Сведение рук сидя пек дек": "Сведение рук в пек-дек", "Сведения рук пек дек": "Сведение рук в пек-дек", - "Сгибание гантелей в стиле молот одновременно": "Гантели молот", - "Сгибание ног": "Сгибание ног сидя", + + # Сгибание ног лежа "Сгибание ног лежа": "Сгибание ног лежа", "Сгибание ног лежа (медленно разгибать)": "Сгибание ног лежа", "Сгибание ног лёжа": "Сгибание ног лежа", + "Сгибания ног лежа": "Сгибание ног лежа", + + # Сгибание ног сидя + "Сгибание ног": "Сгибание ног сидя", "Сгибание ног сидя": "Сгибание ног сидя", "Сгибание ног сидя (3х12)": "Сгибание ног сидя", - "Сгибание рук с гантелями стоя": "Подъем гантелей на бицепс стоя", - "Сгибание рук с гантелями стоя ям": "Подъем гантелей на бицепс стоя", - "Сгибание со штангой стоя (3х12)": "Подъем штанги на бицепс стоя", - "Сгибания ног лежа": "Сгибание ног лежа", - "Сгибания рук со штангой стоя": "Подъем штанги на бицепс стоя", - "Силовой тренажер": "Жим от груди сидя в тренажере (блоки)", + + # Скручивания "Скручивания на мяче": "Скручивания", - "Трацепс": "Отжимание на трицепс в кроссовере", - "Трицепс вниз у стойки": "Отжимание на трицепс в кроссовере", - "Трицепс машина": "Разгибание рук сидя (трицепс машина)", - "Трицепс сидя": "Разгибание рук сидя (трицепс машина)", - "Трицепс-машина (разгибание рук сидя)": "Разгибание рук сидя (трицепс машина)", + + # Тяга Т-грифа "Тяга Т гриф": "Тяга Т-грифа", - "Тяга в наклоне": "Тяга штанги в наклоне", + "Тяга т грифа": "Тяга Т-грифа", + + # Тяга вертикального блока "Тяга вертикального блока": "Тяга вертикального блока", - "Тяга вертикального блока обратным хватом": "Тяга вертикального блока (обратный хват)", "Тяга верхнего блока": "Тяга вертикального блока", + "Тяга вниз сидя": "Тяга вертикального блока", + + # Тяга вертикального блока (обратный хват) + "Тяга вертикального блока обратным хватом": "Тяга вертикального блока (обратный хват)", "Тяга верхнего блока обратным хватом": "Тяга вертикального блока (обратный хват)", "Тяга вниз обратным хватом сидя (фитнес станция)": "Тяга вертикального блока (обратный хват)", - "Тяга вниз сидя": "Тяга вертикального блока", + "Тяга сидя вниз обратным хватом": "Тяга вертикального блока (обратный хват)", + + # Тяга гантелей в наклоне (по очереди) "Тяга гантелей в наклоне": "Тяга гантелей в наклоне (по очереди)", - "Тяга гантелей к поясу лёжа на скамейке 40⁰": "Тяга гантелей на скамье", "Тяга гантелей к поясу стоя в наклоне": "Тяга гантелей в наклоне (по очереди)", - "Тяга гантелей лежа на животе на скамье 80°": "Тяга гантелей на скамье", "Тяга гантели в наклоне": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне (гантеля поочередно)": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне (к поясу одной рукой)": "Тяга гантелей в наклоне (по очереди)", @@ -249,324 +385,43 @@ unique_apple_exercises_mapper = { "Тяга гантели к поясу одной рукой у стойки": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели одной рукой в наклоне": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели одной рукой в стойке": "Тяга гантелей в наклоне (по очереди)", + + # Тяга гантелей на скамье + "Гантели к поясу лежа на скамье": "Тяга гантелей на скамье", + "Тяга гантелей к поясу лёжа на скамейке 40⁰": "Тяга гантелей на скамье", + "Тяга гантелей лежа на животе на скамье 80°": "Тяга гантелей на скамье", + + # Тяга горизонтального блока + "Горизонтальна тяга на себя": "Тяга горизонтального блока", + "Горизонтальная тяга блока": "Тяга горизонтального блока", "Тяга горизонтально блока": "Тяга горизонтального блока", "Тяга горизонтального блок": "Тяга горизонтального блока", "Тяга горизонтального блока": "Тяга горизонтального блока", - "Тяга горизонтального блока (1 рука)": "Тяга горизонтального блока (по очереди)", "Тяга горизонтального блока дю": "Тяга горизонтального блока", - "Тяга горизонтального блока одной рукой": "Тяга горизонтального блока (по очереди)", - "Тяга горизонтального блока одной рукой (поочерёдно)": "Тяга горизонтального блока (по очереди)", "Тяга горизонтального блокай": "Тяга горизонтального блока", "Тяга на себя": "Тяга горизонтального блока", - "Тяга на себя с упором в грудь": "Гребная тяга с упором в грудь", "Тяга на себя сидя": "Тяга горизонтального блока", - "Тяга ногами": "Жим ногами", - "Тяга ногами вниз": "Жим ногами", - "Тяга обратным хватом штанги к поясу": "Тяга штанги в наклоне", + "тяга горизонтального блока": "Тяга горизонтального блока", + + # Тяга горизонтального блока (по очереди) + "Тяга горизонтального блока (1 рука)": "Тяга горизонтального блока (по очереди)", + "Тяга горизонтального блока одной рукой": "Тяга горизонтального блока (по очереди)", + "Тяга горизонтального блока одной рукой (поочерёдно)": "Тяга горизонтального блока (по очереди)", "Тяга одной рукой в кроссовере": "Тяга горизонтального блока (по очереди)", "Тяга одной рукой в кроссовере на колене": "Тяга горизонтального блока (по очереди)", "Тяга руки в кроссовере до": "Тяга горизонтального блока (по очереди)", "Тяга рычага к груди": "Тяга горизонтального блока (по очереди)", - "Тяга сидя вниз обратным хватом": "Тяга вертикального блока (обратный хват)", - "Тяга т грифа": "Тяга Т-грифа", + + # Тяга штанги в наклоне + "Тяга в наклоне": "Тяга штанги в наклоне", "Тяга штанги в наклоне": "Тяга штанги в наклоне", "Тяга штанги в наклоне к груди": "Тяга штанги в наклоне", "Тяга штанги в наклоне к поясу": "Тяга штанги в наклоне", + "Штанга в наклоне": "Тяга штанги в наклоне", + + # Тяга штанги в наклоне (обратным хватом) + "Тяга обратным хватом штанги к поясу": "Тяга штанги в наклоне (обратным хватом)", "Тяга штанги в наклоне к поясу обратным хватом": "Тяга штанги в наклоне (обратным хватом)", "Тяга штанги в наклоне обратным хватом": "Тяга штанги в наклоне (обратным хватом)", "Тяга штанги к поясу в наклоне": "Тяга штанги в наклоне (обратным хватом)", - "Тяга штанги к поясу стоя": "Подъем штанги на бицепс стоя", - "Тяга штанги стоя": "Подъем штанги на бицепс стоя", - "Штанга": "Жим штанги лежа", - "Штанга в наклоне": "Тяга штанги в наклоне", - "Штанга лежа": "Жим штанги лежа", - "Штанга стоя": "Подъем штанги на бицепс стоя", - "тяга горизонтального блока": "Тяга горизонтального блока", -} - - -backup = { - "Батерфляй": 1, - "Баттерфляй": 16, - "Баттерфляй дю": 1, - "Бицепс на лавке 45⁰": 1, - "Болгарский присед": 1, - "Брусья": 1, - "Брусья (гравитрон)": 1, - "Брусья в тренажере": 1, - "Брусья прямые ноги": 1, - "Брусья узким хватом": 1, - "Брусья узким хватом за": 1, - "Брусья широким хватом": 3, - "Брусья-прямые ноги": 1, - "ГАК машина": 1, - "Гакк машина": 3, - "Гакк присед": 2, - "Гантели": 1, - "Гантели к поясу лежа на скамье": 1, - "Гантели молот": 1, - "Гантели на лавках": 1, - "Гантели-молот": 1, - "Гипекстензия": 1, - "Гиперэкстензия": 13, - "Горизонтальна тяга на себя": 1, - "Горизонтальная тяга блока": 1, - "Гравитрон": 30, - "Гравитрор": 1, - "Гребная тяга": 2, - "Гребная тяга с упором в грудь": 7, - "Гребная тяга с упором в грудь как": 1, - "Гребная тяга с упором на грудь": 5, - "Гребная тяга сидя (одна рука)": 1, - "Гребная тяга сидя одной рукой": 1, - "Гребная тяга сидя с упором в грудт": 1, - "Гребная тяга сидя с упором в грудь": 1, - "Гребная тяга сидя с упором в грудь (одной рукой рычаг)": 1, - "Гребная тяга\xa0 упором в грудьс": 1, - "Жим в тренажере вверх": 1, - "Жим в тренажере на плечи блочный (3х12)": 1, - "Жим в тренажёре на плечи (силовой тренажёр: жим сидя)": 1, - "Жим вверх 80⁰": 1, - "Жим гантелей": 3, - "Жим гантелей 45⁰": 3, - "Жим гантелей 60⁰": 1, - "Жим гантелей 80⁰": 3, - "Жим гантелей 90⁰": 3, - "Жим гантелей вверх 80⁰": 1, - "Жим гантелей вверх 90⁰": 1, - "Жим гантелей вверх сидя 90⁰": 1, - "Жим гантелей лежа": 10, - "Жим гантелей лежа 15⁰": 1, - "Жим гантелей лежа 30⁰": 1, - "Жим гантелей лежа на скамье": 1, - "Жим гантелей лёжа": 3, - "Жим гантелей лёжа на скамье": 2, - "Жим гантелей на скамье": 1, - "Жим гантелей на скамье 45⁰": 1, - "Жим гантелей сидя": 3, - "Жим гантелей сидя 80⁰": 2, - "Жим гантелей сидя 90⁰": 2, - "Жим гантелей сидя на скамейке": 1, - "Жим гантелей стоя": 2, - "Жим л груди в тренажёре": 1, - "Жим лежа": 6, - "Жим ногами": 15, - "Жим ногами (3х15)": 1, - "Жим ногами (медленно вниз)": 1, - "Жим ногами лежа": 1, - "Жим ногами медленно": 1, - "Жим от груди": 2, - "Жим от груди (сидя, тренажёр)": 1, - "Жим от груди в тренажере сидя": 1, - "Жим от груди в тренажёре (кирпичики)": 1, - "Жим от груди сидя": 5, - "Жим от груди сидя (блинчики)": 2, - "Жим от груди сидя в тренажере": 3, - "Жим от груди сидя в тренажере (около трицепс машины)": 1, - "Жим от груди сидя в тренажере (рычаги)": 1, - "Жим от груди сидя в тренажере рычаги": 1, - "Жим от груди сидя в тренажёре": 3, - "Жим от груди сидя в тренажёре (блинчики)": 1, - "Жим от груди сидя в тренажёре (рычаги)": 1, - "Жим от плеч (рычаги)": 1, - "Жим от плеч вверх": 12, - "Жим от плеч вверх в тренажёре": 1, - "Жим от плеч вверх сидя": 1, - "Жим от плеч вверх сидя 80⁰": 1, - "Жим от плеч вверх сидя в тренажере": 1, - "Жим от плеч сидя": 2, - "Жим от плеч сидя (рычаги)": 3, - "Жим от плеч сидя зэ": 1, - "Жим от плеч сидя хз": 1, - "Жим от плечей вверх": 1, - "Жим плечами вверх сидя": 1, - "Жим сидя 45⁰": 1, - "Жим штанги 45⁰": 2, - "Жим штанги в наклоне": 1, - "Жим штанги лежа": 1, - "Жим штанги сидя 45⁰": 1, - "Жим штанги стля": 1, - "Жим штанги стоя": 1, - "Жис гантелей лежа": 1, - "Жис сидя в тренажёре": 1, - "Махи в наклоне с упором": 1, - "Молот назад двумя руками": 1, - "Молот трицепс стоя": 1, - "Молоты": 1, - "Наклонная тяга (скамья)": 1, - "Наклоны с прямой спиной": 1, - "Отведение в кроссовере одной рукой": 1, - "Отведение в рук в наклоне": 1, - "Отведение назад в пек дек": 1, - "Отведение назад в тренажере пек дек": 1, - "Отведение назад в тренажере пэк дэк (3х12)": 1, - "Отведение рук в кроссовере": 1, - "Отведение рук в стороны с гантелями стоя": 1, - "Отведение рук в стороны стоя с гантелями": 1, - "Отведение рук назад в пек дек": 1, - "Отведение рук с гантелями стоя": 2, - "Отведение рук стоя с гантелями": 1, - "Отведение руки в кроссовере": 2, - "Отведение руки в кроссовере (одной рукой)": 1, - "Отведение руки в кроссовере (по одной руке)": 2, - "Отведение руки в кроссовере на каждую руку": 1, - "Отведение руки в кроссовкре": 1, - "Отведение руки в сторону": 1, - "Отведение руки в сторону в кроссовере (каждая рука)": 1, - "Отведение руки стоя": 2, - "Отведение руки стоя снизу вверх": 1, - "Отжимания": 16, - "Отжимания на брусьях": 7, - "Отжимания на брусьях узким хватом": 1, - "Отжимания на брусьях широким хватом": 3, - "Пек дек (отведение назад)": 1, - "Пек дек разведение рук в стороны": 1, - "Подтягивание на заднюю дельту в петлях": 1, - "Подтягивание ног на ручнике": 1, - "Подтягивание ног на турнике": 2, - "Подтягивание ног прямых вися на турнике": 1, - "Подтягивания": 8, - "Подтягивания в гравитроне": 1, - "Подтягивания на резинке": 1, - "Подтягивания обратным хватом": 8, - "Подтяотвания": 1, - "Подъем коленей на турнике": 1, - "Подъем ног на турнике": 4, - "Подъем штанги стоя": 2, - "Подъёмы ног на турнике": 1, - "Подьем штанги стоя": 1, - "Присд на одну ногу (по очереди)": 1, - "Присед на одну ногу": 1, - "Присед на одну ногу (каждая)": 1, - "Приседания": 16, - "Приседания на одной ноге": 1, - "Разведение рук в кроссовере на трицепс": 1, - "Разведение рук в наклоне": 2, - "Разведение рук в налоне": 1, - "Разведение рук в пек дек": 6, - "Разведение рук в стороны": 14, - "Разведение рук в стороны (дельт-машина)": 3, - "Разведение рук в стороны (дельта-машина)": 1, - "Разведение рук в стороны (пек дек)": 1, - "Разведение рук в стороны в наклоне 90⁰": 2, - "Разведение рук в стороны в наклоне с гантелями": 1, - "Разведение рук в стороны в пекдек": 1, - "Разведение рук в стороны в тренажёре": 1, - "Разведение рук в стороны в тренажёре Дж": 1, - "Разведение рук в стороны пек дек": 2, - "Разведение рук в стороны с гантелям": 1, - "Разведение рук в стороны стоя": 2, - "Разведение рук в стороны стоя с гантелями": 2, - "Разведение рук в стрроны": 1, - "Разведение рук назад в пек дек": 1, - "Разведение рук назад пек дек": 1, - "Разведение рук пек дек": 4, - "Разведение рук сидя": 3, - "Разведение рук сидя с прямыми руками в тренажере": 1, - "Разведение рук стоя с гантелями": 1, - "Разгибание из за головы": 1, - "Разгибание кик-бек": 1, - "Разгибание локтей в наклоне": 1, - "Разгибание ног": 5, - "Разгибание ног сидя": 22, - "Разгибание ног сидя (4х10)": 1, - "Разгибание прямых рук сидя": 1, - "Разгибание рук в кроссовере": 1, - "Разгибание рук в тренажёре для трицепса": 1, - "Разгибание рук в трицепс машине (3х10)": 1, - "Разгибание рук сидя": 5, - "Разгибание рук сидя (локти в стороны)": 1, - "Разгибание рук сидя (трицепс машина)": 1, - "Разгибание рук стоя с канатом": 1, - "Разгибание спины": 1, - "Румынская тяга": 5, - "Румынская тяга с гантелями": 1, - "Румынская тяна": 2, - "Румынская тяоа": 1, - "Сведение на скамейке": 1, - "Сведение рук в пек дек": 8, - "Сведение рук в пек дек зэ": 1, - "Сведение рук в тренажере": 1, - "Сведение рук в тренажёре пёк дек": 1, - "Сведение рук пек дек": 7, - "Сведение рук пек дек (бабочка)": 1, - "Сведение рук сидя": 3, - "Сведение рук сидя пек дек": 1, - "Сведения рук пек дек": 1, - "Сгибание гантелей в стиле молот одновременно": 1, - "Сгибание ног": 2, - "Сгибание ног лежа": 14, - "Сгибание ног лежа (медленно разгибать)": 1, - "Сгибание ног лёжа": 2, - "Сгибание ног сидя": 8, - "Сгибание ног сидя (3х12)": 1, - "Сгибание рук с гантелями стоя": 1, - "Сгибание рук с гантелями стоя ям": 1, - "Сгибание со штангой стоя (3х12)": 1, - "Сгибания ног лежа": 1, - "Сгибания рук со штангой стоя": 1, - "Силовой тренажер": 1, - "Скручивания на мяче": 2, - "Трацепс": 1, - "Трицепс вниз у стойки": 1, - "Трицепс машина": 4, - "Трицепс сидя": 1, - "Трицепс-машина (разгибание рук сидя)": 1, - "Тяга Т гриф": 1, - "Тяга в наклоне": 1, - "Тяга вертикального блока": 15, - "Тяга вертикального блока обратным хватом": 5, - "Тяга верхнего блока": 3, - "Тяга верхнего блока обратным хватом": 1, - "Тяга вниз обратным хватом сидя (фитнес станция)": 1, - "Тяга вниз сидя": 2, - "Тяга гантелей в наклоне": 3, - "Тяга гантелей к поясу лёжа на скамейке 40⁰": 1, - "Тяга гантелей к поясу стоя в наклоне": 1, - "Тяга гантелей лежа на животе на скамье 80°": 1, - "Тяга гантели в наклоне": 4, - "Тяга гантели в наклоне (гантеля поочередно)": 1, - "Тяга гантели в наклоне (к поясу одной рукой)": 1, - "Тяга гантели в наклоне одной рукой": 1, - "Тяга гантели к корпусу в наклоне же": 1, - "Тяга гантели к поясу": 1, - "Тяга гантели к поясу в наклоне": 1, - "Тяга гантели к поясу в наклоне одной рукой": 1, - "Тяга гантели к поясу в стойке": 1, - "Тяга гантели к поясу одной рукой у стойки": 1, - "Тяга гантели одной рукой в наклоне": 1, - "Тяга гантели одной рукой в стойке": 1, - "Тяга горизонтально блока": 1, - "Тяга горизонтального блок": 1, - "Тяга горизонтального блока": 14, - "Тяга горизонтального блока (1 рука)": 1, - "Тяга горизонтального блока дю": 1, - "Тяга горизонтального блока одной рукой": 4, - "Тяга горизонтального блока одной рукой (поочерёдно)": 1, - "Тяга горизонтального блокай": 1, - "Тяга на себя": 3, - "Тяга на себя с упором в грудь": 1, - "Тяга на себя сидя": 3, - "Тяга ногами": 1, - "Тяга ногами вниз": 1, - "Тяга обратным хватом штанги к поясу": 1, - "Тяга одной рукой в кроссовере": 1, - "Тяга одной рукой в кроссовере на колене": 1, - "Тяга руки в кроссовере до": 1, - "Тяга рычага к груди": 1, - "Тяга сидя вниз обратным хватом": 1, - "Тяга т грифа": 1, - "Тяга штанги в наклоне": 7, - "Тяга штанги в наклоне к груди": 1, - "Тяга штанги в наклоне к поясу": 1, - "Тяга штанги в наклоне к поясу обратным хватом": 1, - "Тяга штанги в наклоне обратным хватом": 1, - "Тяга штанги к поясу в наклоне": 1, - "Тяга штанги к поясу стоя": 1, - "Тяга штанги стоя": 1, - "Штанга": 2, - "Штанга в наклоне": 1, - "Штанга лежа": 1, - "Штанга стоя": 1, - "тяга горизонтального блока": 1, } diff --git a/app/core/parsers/base.py b/app/core/parsers/base.py index c8e960a..4b10e6a 100644 --- a/app/core/parsers/base.py +++ b/app/core/parsers/base.py @@ -1,7 +1,7 @@ import os from typing import List, Tuple, Dict, Optional -from app.core.models.training import Approach, Exercise, Training +from app.core.dto.training import ApproachDTO, ExerciseDTO, TrainingDTO from app.core.utils.date_refactor import parse_training_date @@ -25,7 +25,7 @@ class BaseNotesParser: content = f.read() return content - def serialize_exercise(self, reps: str, weight: str, name: str) -> Exercise: + def serialize_exercise(self, reps: str, weight: str, name: str) -> ExerciseDTO: """Convert raw exercise data into Exercise object with approaches.""" reps_list: List[int] = [int(rep) for rep in reps.split("-")] weight_splitted: bool = False @@ -45,24 +45,24 @@ class BaseNotesParser: approaches = [] if not weight: for rep_index in range(0, len(reps_list)): - approach = Approach(weight=0.0, reps=reps_list[rep_index]) + approach = ApproachDTO(weight=0.0, reps=reps_list[rep_index]) approaches.append(approach) else: weight_pointer = 0 for rep_index in range(0, len(reps_list)): - approach = Approach( + approach = ApproachDTO( weight=weight_list[weight_pointer], reps=reps_list[rep_index] ) if rep_index < len(weight_list) - 1: weight_pointer += 1 approaches.append(approach) - exercise = Exercise( + exercise = ExerciseDTO( name=name, approaches=approaches, splitted_weight=weight_splitted ) return exercise - def parse_training_exercises(self, exercise_line: str) -> Exercise: + def parse_training_exercises(self, exercise_line: str) -> ExerciseDTO: """Parse exercise data from a table row.""" stripped: List[str] = [entry.strip() for entry in exercise_line.split("|")][ 1:-1 @@ -90,11 +90,11 @@ class BaseNotesParser: """Parse training header. Override in subclasses for specific formats.""" raise NotImplementedError("Subclasses must implement parse_training_header") - def create_training_from_date(self, date_str: str) -> Training: + def create_training_from_date(self, date_str: str) -> TrainingDTO: """Create Training object from date string using utility function.""" - return Training(date=parse_training_date(date_str), exercises=[]) + return TrainingDTO(date=parse_training_date(date_str), exercises=[]) - def parse_training_data(self) -> List[Training]: + def parse_training_data(self) -> List[TrainingDTO]: """Main parsing method. Override for specific parsing logic.""" training_data = self.filter_training_data( self.read_data_file(self.data_file_name) @@ -120,7 +120,7 @@ class BaseNotesParser: return [train for train in trains if train is not None] - def apply_exercise_mapping(self, trainings: List[Training]) -> List[Training]: + def apply_exercise_mapping(self, trainings: List[TrainingDTO]) -> List[TrainingDTO]: """Apply exercise name mapping to all trainings.""" for training in trainings: if not training or not training.exercises: @@ -133,7 +133,7 @@ class BaseNotesParser: exercise.name = mapped_name return trainings - def parse_and_map_training_data(self) -> List[Training]: + def parse_and_map_training_data(self) -> List[TrainingDTO]: """Parse training data and apply exercise mapping.""" trainings = self.parse_training_data() return self.apply_exercise_mapping(trainings) diff --git a/app/core/parsers/obsidian.py b/app/core/parsers/obsidian.py index 8cee048..a97366d 100644 --- a/app/core/parsers/obsidian.py +++ b/app/core/parsers/obsidian.py @@ -1,7 +1,7 @@ import re from typing import List, Tuple -from app.core.models.training import Training +from app.core.dto.training import TrainingDTO from app.core.parsers.obsidian_mapper import obsidian_unique_exercies_mapping from app.core.parsers.base import BaseNotesParser @@ -11,7 +11,7 @@ class ObsidianNotesParser(BaseNotesParser): def __init__(self): super().__init__( - data_file_name="obsidian.md", + data_file_name="complete_data/obsidian.md", exercise_mapper=obsidian_unique_exercies_mapping, ) @@ -35,7 +35,7 @@ class ObsidianNotesParser(BaseNotesParser): return True, date, trainer, year_count return False, "", "", "" - def parse(self, data: str) -> List[Training]: + def parse(self, data: str) -> List[TrainingDTO]: """Parse Obsidian training data from string input.""" # Override the data file reading with direct string input original_method = self.read_data_file @@ -49,13 +49,13 @@ class ObsidianNotesParser(BaseNotesParser): self.read_data_file = original_method -def parse_training_data() -> List[Training]: +def parse_training_data() -> List[TrainingDTO]: """Parse Obsidian Notes training data.""" parser = ObsidianNotesParser() return parser.parse_training_data() -def remap_unique_exercises(obsidian_trainings: List[Training]) -> List[Training]: +def remap_unique_exercises(obsidian_trainings: List[TrainingDTO]) -> List[TrainingDTO]: """Remap exercise names using Obsidian-specific mapping (deprecated - use parser.parse_and_map_training_data()).""" parser = ObsidianNotesParser() return parser.apply_exercise_mapping(obsidian_trainings) diff --git a/app/core/parsers/obsidian_mapper.py b/app/core/parsers/obsidian_mapper.py index e6b5092..4b5b60b 100644 --- a/app/core/parsers/obsidian_mapper.py +++ b/app/core/parsers/obsidian_mapper.py @@ -40,124 +40,335 @@ list_of_unique_names = [ "Жим от груди сидя в тренажере (рычаги)", "Жим от плеч вверх в тренажере (рычаги)", "Икроножные сидя", - "Пресс на наклонной скамье" + "Пресс на наклонной скамье", + "Бицепс машина", + "Pull down (блины)", + "Pull down", + "Тяга Т-грифа", + "Французский жим гантели сидя", + "Молоты стоя (наискосок)", + "Отведение руки из-за спины в кроссовере", + "Гребная тяга с упором в грудь", + "Тяга штанги в наклоне", + "Молоты с гантелями лёжа", + "Махи гантелей стоя", + "Жим штанги лежа", + "Подъем штанги стоя", + "Подъем гантелей на предплечья обратным хватом", + "Жим от плеч вверх в тренажёре (блины)", + "Жим от плеч вверх в тренажёре (кирпичики)" ] obsidian_unique_exercies_mapping = { + # Подъем ног в висе + "Подьем ног в висе": "Подъем ног в висе", + "Подъем ног в висе": "Подъем ног в висе", + "Подъём ног в висе": "Подъем ног в висе", + + # Подъем штанги стоя + "Подъем штанги на бицепс стоя": "Подъем штанги стоя", + "Подьем штанги на бицепс": "Подъем штанги стоя", + "Подъём штанги стоя": "Подъем штанги стоя", + "Подьем штанги стоя": "Подъем штанги стоя", + "Разведение рук в стороны с гантелями стоя": "Подъем штанги стоя", + "Сгибание штанги стоя на бицепс": "Подъем штанги стоя", + + + # Подъем гантелей на предплечья обратным хватом + 'Подъем гантелей на предплечье обратным хватом': 'Подъем гантелей на предплечья обратным хватом', + 'Подъем гартелей на предплечье обратным хватом': 'Подъем гантелей на предплечья обратным хватом', + + # Баттерфляй "Баттерфляй": "Баттерфляй", + + # Бицепс машина + "Бицепс-машина": "Бицепс машина", + "Бицепс в тренажёре": "Бицепс машина", + "Бицепс в тренажёре (arm curl)": "Бицепс машина", + + # Болгарские сплит-приседания "Болгарские приседания на одну ногу": "Болгарские сплит-приседения", + + # Брусья "Брусья": "Брусья", "Брусья узким хватом": "Брусья", + + # Вертикальная тяга одной рукой "Вертикальная тяга одной рукой 45⁰": "Вертикальная тяга одной рукой", + + # Выпады "Выпады вперед по очереди каждой ногой": "Выпады", "Выпады с гантелями на одну ногу вперед": "Выпады", + "Выпады вперед с гантелями на одну ногу": "Выпады", + + # Гиперэкстензия "Гиперэкстензия": "Гиперэкстензия", + + # Гравитрон "Гравитрон": "Гравитрон", "Гравитрон (медленно вниз)": "Гравитрон", + + # Гребная тяга с упором в грудь "Гребная тяга с упорм в грудь": "Гребная тяга с упором в грудь", "Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь", + + # Гребная тяга с упором в грудь (по очереди) "Гребная тяга с упором в грудь (одна рука)": "Гребная тяга с упором в грудь (по очереди)", - "Дельт машина": "Разведение рук в стороны (дельт-машина)", - "Дельт машина (разведение рук в стороны)": "Разведение рук в стороны (дельт-машина)", + + # Жим гантелей лежа "Жим гантелей лежа": "Жим гантелей лежа", "Жим гантелей лежа на скамье": "Жим гантелей лежа", - "Жим гантелей лежа на скамье 30⁰": "Жим гантелей лежа (Под углом 45 градусов)", "Жим гантелей лёжа": "Жим гантелей лежа", + "Жим гантелей от груди лежа": "Жим гантелей лежа", + "Жим от груди лежа с гантелями": "Жим гантелей лежа", + + # Жим гантелей лежа (Под углом 45 градусов) + "Жим гантелей лежа на скамье 30⁰": "Жим гантелей лежа (Под углом 45 градусов)", "Жим гантелей лёжа на скамейке 45⁰": "Жим гантелей лежа (Под углом 45 градусов)", "Жим гантелей на скамье 65⁰": "Жим гантелей лежа (Под углом 45 градусов)", + + # Жим гантелей сидя "Жим гантелей сидя": "Жим гантелей сидя", "Жим гантелей сидя 80⁰": "Жим гантелей сидя", "Жим гантелей сидя 85⁰": "Жим гантелей сидя", "Жим гантелей сидя 8⁰": "Жим гантелей сидя", "Жим гантелей сидя 90⁰": "Жим гантелей сидя", "Жим гантелей сидя на скамье": "Жим гантелей сидя", + "Жим гантелей силя с гантелями": "Жим гантелей сидя", + "Жим от плеч вверх с гантелями": "Жим гантелей сидя", + "Жим от плеч вверх сидя": "Жим гантелей сидя", + "Жим от плеч вверх сидя с гантелями": "Жим гантелей сидя", + "Жим от плеч сидя с гантелями": "Жим гантелей сидя", + "Жим от плеч сидя": "Жим гантелей сидя", + + # Жим ногами "Жим ногами": "Жим ногами", "Жим ногами ш-ш-ш": "Жим ногами", + "Жим ногамиш": "Жим ногами", + + # Жим от груди сидя в тренажере (рычаги) "Жим от груди (рычаги)": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди рычаги": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя (рычаги)": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя в тренажере (рычаги)": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя в тренажёре (рычаги)": "Жим от груди сидя в тренажере (рычаги)", "Жим от груди сидя рычаги": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди в тренажёре сидя (рычаги)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажере (блинчики)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре (блинчики)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре (блины)": "Жим от груди сидя в тренажере (рычаги)", + "Жим от груди сидя в тренажёре (рычаги, блинчики)": "Жим от груди сидя в тренажере (рычаги)", + + # Жим от плеч вверх в тренажере (рычаги) "Жим от плеч вверх (тренажёр, рычаги)": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч вверх в тренажёре": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч вверх рычаги": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч сидя (рычаги наверху)": "Жим от плеч вверх в тренажере (рычаги)", "Жим от плеч сидя в тренажере (рычаги)": "Жим от плеч вверх в тренажере (рычаги)", + "Жим от плеч вверх (рычаги)": "Жим от плеч вверх в тренажере (рычаги)", + "Жим от плеч вверх в тренажёре (рычаги)": "Жим от плеч вверх в тренажере (рычаги)", + + # Жим от плеч вверх в тренажере (блины) + "Жим от плеч вверх сидя в тренажёре (блинчики)":"Жим от плеч вверх в тренажёре (блины)", + "Жим от плеч сидя в тренажёре (блинчики)":"Жим от плеч вверх в тренажёре (блины)", + + # Жим от плеч вверх в тренажере (кирпичики) + "Жим от плеч вверх сидя в тренажёре (кирпичики)":"Жим от плеч вверх в тренажёре (кирпичики)", + + # Жим штанги лежа + "Жим штанги лёжа": "Жим штанги лежа", + + # Икроножные сидя "Икроножные сидя": "Икроножные сидя", "Икроножные сидя за": "Икроножные сидя", - "Кроссовер - отжимание на трицепс": "Отжимание на трицепс в кроссовере", + + # Махи гантелей стоя + "Разведение рук в стороны стоя (гантели)": "Махи гантелей стоя", + "Разведение рук в стороны стоя с гантелями": "Махи гантелей стоя", + "Разведение рук стоя": "Махи гантелей стоя", + "Разведение рук с гантелями стоя": "Махи гантелей стоя", + "Разведение рук в стороны стоя": "Махи гантелей стоя", + "Разведение рук в стороны с гантелями": "Махи гантелей стоя", + + # Молоты с гантелями лёжа + "Молоты лежа": "Молоты с гантелями лёжа", + "Молоты лёжа": "Молоты с гантелями лёжа", + "Молоты с гантелями лежа": "Молоты с гантелями лёжа", + + # Молоты стоя (наискосок) + 'Молоты стоя наискосок': 'Молоты стоя (наискосок)', + + # Отведение рук в кроссовере (по очереди) "Мах руки в кроссовере": "Отведение рук в кроссовере (по очереди)", "Отведение плеча в сторону в кроссовере": "Отведение рук в кроссовере (по очереди)", "Отведение руки в кроссовере из за спины": "Отведение рук в кроссовере (по очереди)", "Отведение руки в кроссовере по очереди каждую руку": "Отведение рук в кроссовере (по очереди)", - "Отведение руки в пек дек (по очереди каждой рукой)": "Разведение рук в пек-дек (по очереди)", - "Отведение руки в пек дек (по очереди)": "Разведение рук в пек-дек (по очереди)", "Отведение руки в сторону (дефоли) в кроссовере": "Отведение рук в кроссовере (по очереди)", - "Отведение руки назад в кроссовере (аналог пек дек одной рукой)": "Разведение рук в пек-дек (по очереди)", + "Отведение руки в кроссовере": "Отведение рук в кроссовере (по очереди)", + + # Отведение руки из-за спины в кроссовере + 'Отведение руки из-за спины': 'Отведение руки из-за спины в кроссовере', + + # Отжимание на трицепс в кроссовере + "Кроссовер - отжимание на трицепс": "Отжимание на трицепс в кроссовере", + "Отдикна трицепс в кроссовере": "Отжимание на трицепс в кроссовере", + "Отжимания на брусьях": "Отжимание на трицепс в кроссовере", + "Отжимания на трицепс": "Отжимание на трицепс в кроссовере", + "Кроссовер: отжимание на трицепс": "Отжимание на трицепс в кроссовере", + "Кроссовер: отжимания на трицепс": "Отжимание на трицепс в кроссовере", + "Отжимания на трицепс в кроссовере": "Отжимание на трицепс в кроссовере", + "Отличается на трицепс в кроссовере": "Отжимание на трицепс в кроссовере", + "Трицепс в кроссовере": "Отжимание на трицепс в кроссовере", + + # Отжимания "Отжимания": "Отжимания", + + # Подтягивания "Подтягивания": "Подтягивания", - "Подтягивания обратным хватом": "Подтягивания обратным хватом", "Подтянивания": "Подтягивания", - "Подъём ног в висе": "Подъём ног в висе", + + # Подтягивания обратным хватом + "Подтягивание обратным хватом": "Подтягивания обратным хватом", + + # Подъем гантелей на бицепс стоя + "Сгибание рук с гантелями стоя (супинирование?)": "Подъем гантелей на бицепс стоя", + "Подъем гантелей на бицепс": "Подъем гантелей на бицепс стоя", + "Подъем гантелей стоя": "Подъем гантелей на бицепс стоя", + "Подъём гантелей на бицепс": "Подъем гантелей на бицепс стоя", + "Подъём гантелей стоя": "Подъем гантелей на бицепс стоя", + "Подьем гантелей на бицепс стоя": "Подъем гантелей на бицепс стоя", + "Подьем гантелей стоя": "Подъем гантелей на бицепс стоя", + "Сгибание на бицепс с гантелями": "Подъем гантелей на бицепс стоя", + + + + # Пресс на наклонной скамье + "Пресс на скамье": "Пресс на наклонной скамье", + "Пресс на скамейке": "Пресс на наклонной скамье", + + # Приседания "Приседания": "Приседания", - "Разведение рук а стороны сидя": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", - "Разведение рук в наклоне сидя": "Разведение рук в стороны в наклоне (гантели)", - "Разведение рук в стороны": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны (дельт машина)": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны в наклоне с гантелями": "Разведение рук в стороны в наклоне (гантели)", - "Разведение рук в стороны в тренажаре": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны с гантелями стоя": "Разведение рук в стороны стоя (гантели)", - "Разведение рук в стороны сидя": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны сидя спиной к тренажеру": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стороны стоя": "Разведение рук в стороны стоя (гантели)", - "Разведение рук в строоны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", - "Разведение рук в стророны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", + + # Pull down + "Pull down (кирпичики)": "Pull down", + "Pull down в тренажёре (кирпичи)": "Pull down", + "Тяга вертикального блока (кирпичики)": "Pull down", + "Тяга вертикального блока в тренажёре (кирпичики)": "Pull down", + + # Pull down (блины) + "Pull down (блины на рычагах)": "Pull down (блины)", + "Вертикальная тяга - рычаги (pull down)": "Pull down (блины)", + "Вертикальная тяга - рычаги с блинами (pull down)": "Pull down (блины)", + "Вертикальная тяга - рычги (pull down)": "Pull down (блины)", + + # Разведение рук в пек-дек "Разведение рук назад в пек дек": "Разведение рук в пек-дек", "Разведение рук назад пёк дек": "Разведение рук в пек-дек", "Разведение рук пек дек": "Разведение рук в пек-дек", "Разведение рук пёк дек": "Разведение рук в пек-дек", + "Разведение рук пек-дек": "Разведение рук в пек-дек", + "Разведение рук назад пек дек": "Разведение рук в пек-дек", + + # Разведение рук в пек-дек (по очереди) + "Отведение руки в пек дек (по очереди каждой рукой)": "Разведение рук в пек-дек (по очереди)", + "Отведение руки в пек дек (по очереди)": "Разведение рук в пек-дек (по очереди)", + "Отведение руки назад в кроссовере (аналог пек дек одной рукой)": "Разведение рук в пек-дек (по очереди)", + + # Разведение рук в стороны (дельт-машина) + "Дельт машина": "Разведение рук в стороны (дельт-машина)", + "Дельт машина (разведение рук в стороны)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук а стороны сидя": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны (дельт машина)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны в тренажаре": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны сидя": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стороны сидя спиной к тренажеру": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в строоны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук в стророны (дельт-машина)": "Разведение рук в стороны (дельт-машина)", + "Разведение рук а стороны (Дельт машина)": "Разведение рук в стороны (дельт-машина)", + + # Разведение рук в стороны в наклоне (гантели) + "Разведение рук в наклоне": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в наклоне сидя": "Разведение рук в стороны в наклоне (гантели)", + "Разведение рук в стороны в наклоне с гантелями": "Разведение рук в стороны в наклоне (гантели)", + + # Разгибание ног сидя "Разгибание ног сидя": "Разгибание ног сидя", + + # Разгибание рук сидя (трицепс машина) "Разгибание рук сидя (трицепс машина)": "Разгибание рук сидя (трицепс машина)", + "Трицепс машина": "Разгибание рук сидя (трицепс машина)", + + # Румынская тяга "Румынская тяга": "Румынская тяга", + + # Сведение рук в пек-дек "Сведение пек дек": "Сведение рук в пек-дек", "Сведение рук в пек дек": "Сведение рук в пек-дек", "Сведение рук в пек декх": "Сведение рук в пек-дек", "Сведение рук пек дек": "Сведение рук в пек-дек", "Сведение рук пёк дек": "Сведение рук в пек-дек", + "Сведение рук в пёк дек": "Сведение рук в пек-дек", + "Сведение рук пек-дек": "Сведение рук в пек-дек", + + # Сгибание ног лежа "Сгибание ног лежа": "Сгибание ног лежа", "Сгибание ног лёжа": "Сгибание ног лежа", + + # Сгибание ног сидя "Сгибание ног сидя": "Сгибание ног сидя", - "Сгибание рук с гантелями стоя (супинирование?)": "Подъем гантелей на бицепс стоя", - "Сгибание штанги стоя на бицепс": "Подъем штанги на бицепс стоя", - "Трицепс машина": "Разгибание рук сидя (трицепс машина)", + + # Тяга Т-грифа + 'Тяга Т грифа': 'Тяга Т-грифа', + 'Тяга т-грифа': 'Тяга Т-грифа', + + # Тяга вертикального блока "Тяга вертикального блока": "Тяга вертикального блока", - "Тяга вертикального блока обратным хватом": "Тяга вертикального блока (обратный хват)", "Тяга вертикального блока прямым хватом": "Тяга вертикального блока", "Тяга верхнего блока": "Тяга вертикального блока", "Тяга верхнего блока за": "Тяга вертикального блока", + "Тяга вертикалього блока": "Тяга вертикального блока", + + # Тяга вертикального блока (обратный хват) + "Тяга вертикального блока обратным хватом": "Тяга вертикального блока (обратный хват)", + "Тяга вертикалього блока обратным хватом": "Тяга вертикального блока (обратный хват)", + + # Тяга вертикального блока (блины) + "Тяга вертикального блока в тренажёре (рычаги)": "Тяга вертикального блока (блины)", + "Тяга вертикально блока (блинчики)": "Тяга вертикального блока (блины)", + + # Тяга гантелей в наклоне (по очереди) "Тяга гантелей в наклоне": "Тяга гантелей в наклоне (по очереди)", - "Тяга гантелей к поясу лёжа на животе на скамье": "Тяга гантелей на скамье", - "Тяга гантелей лежа на животе на скамье 80°": "Тяга гантелей на скамье", - "Тяга гантелей на скамье": "Тяга гантелей на скамье", "Тяга гантели в наклоне": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне 1 рукой": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне к поясу к стойки": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)", "Тяга гантели в наклоне одной рукой (каждой)": "Тяга гантелей в наклоне (по очереди)", + "Тяга гантелей в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)", + "Тяга гантели к поясу в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)", + + # Тяга гантелей на скамье + "Тяга гантелей к поясу лёжа на животе на скамье": "Тяга гантелей на скамье", + "Тяга гантелей лежа на животе на скамье 80°": "Тяга гантелей на скамье", + "Тяга гантелей на скамье": "Тяга гантелей на скамье", "Тяга гантели лежа в наклоне на скамье": "Тяга гантелей на скамье", - "Тяга горизонтально блока одной рукой": "Тяга горизонтального блока (по очереди)", + "Тяга гантелей к поясу лежа на скамье": "Тяга гантелей на скамье", + + # Тяга горизонтального блока "Тяга горизонтального блока": "Тяга горизонтального блока", + + # Тяга горизонтального блока (по очереди) + "Тяга горизонтально блока одной рукой": "Тяга горизонтального блока (по очереди)", "Тяга горизонтального блока 1 рукой поочерёдно": "Тяга горизонтального блока (по очереди)", "Тяга горизонтального блока одной рукой": "Тяга горизонтального блока (по очереди)", - "Пресс на скамье": "Пресс на наклонной скамье", - "Пресс на скамейке": "Пресс на наклонной скамье", - "Отжимания на трицепс":"Отжимания на трицепс в кроссовере", - "Молоты лежа":"Молоты с гантелями лёжа", - "Молоты лёжа":"Молоты с гантелями лёжа", - "Молоты с гантелями лежа":"Молоты с гантелями лёжа", -} + # Тяга штанги в наклоне + "Тяга штанги к поясу в наклоне": "Тяга штанги в наклоне", + + # Французский жим гантели сидя + 'Французский жим с гантелей': 'Французский жим гантели сидя', + 'Французский жим сидя': 'Французский жим гантели сидя', +} diff --git a/app/core/parsers/text_data.py b/app/core/parsers/text_data.py index 13dcfaa..294217c 100644 --- a/app/core/parsers/text_data.py +++ b/app/core/parsers/text_data.py @@ -1,9 +1,9 @@ from typing import List from app.core.parsers.apple import AppleNotesParser from app.core.parsers.obsidian import ObsidianNotesParser -from app.core.models.training import Training +from app.core.dto.training import TrainingDTO -def parse_old_data() -> List[Training]: +def parse_old_data() -> List[TrainingDTO]: """Method for parsing all old data from apple and obsidian notes with exercise mapping applied Returns: diff --git a/app/main.py b/app/main.py index a394083..d852401 100644 --- a/app/main.py +++ b/app/main.py @@ -1,13 +1,35 @@ +import logging +from contextlib import asynccontextmanager + from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates + from app.api.v1.api import api_router from app.api.v1.web import web_router +from app.config import settings +from migrations.runner import MigrationRunner +# TODO: Replace level with settings value +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + logging.info(f"\n\n{settings.get_postgres_database_url()}") + runner = MigrationRunner(settings.get_postgres_database_url()) + await runner.run_migrations() + yield + + +# TODO: (#ToLearn) Почитать про lifespan в FastAPI приложениях app = FastAPI( title="Fitness Parser API", description="API for parsing fitness training data from various sources", version="0.1.0", + lifespan=lifespan, ) app.mount("/static", StaticFiles(directory="app/static"), name="static") diff --git a/app/sandbox.py b/app/sandbox.py new file mode 100644 index 0000000..b7956ab --- /dev/null +++ b/app/sandbox.py @@ -0,0 +1,27 @@ +from collections import defaultdict +from app.core.parsers.apple import AppleNotesParser +from app.core.parsers.obsidian import ObsidianNotesParser +from pprint import pprint + + +om = ObsidianNotesParser() +o_mapped_trainings = om.parse_training_data() + +am = AppleNotesParser() +a_mapped_trainings = am.parse_training_data() + +combined_list = o_mapped_trainings + a_mapped_trainings +print(len(combined_list)) + +comb_uniques_names = defaultdict(int) +exercise_names = list() + +for training in combined_list: + if training.exercises: + for exercise in training.exercises: + exercise_names.append(exercise.name) + comb_uniques_names[exercise.name] += 1 + + +# pprint(set(exercise_names)) +pprint(comb_uniques_names) diff --git a/app/templates/base.html b/app/templates/base.html index 503835c..ab1b48e 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -13,7 +13,8 @@