Compare commits
13 commits
main
...
7-Add-data
| Author | SHA1 | Date | |
|---|---|---|---|
| d2ea2a39e6 | |||
| e580ab7b7e | |||
| 096e52ed3f | |||
| 6c0de96bed | |||
| c69c700f2b | |||
| ff59ae3ee9 | |||
| d0407e3462 | |||
| 4aa8b7a5c3 | |||
| 5c8a4566bd | |||
| 4ccdc39529 | |||
| 6974cca514 | |||
| 618e30c9d8 | |||
| 53a7983497 |
37 changed files with 1450 additions and 533 deletions
12
.env.example
Normal file
12
.env.example
Normal file
|
|
@ -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
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -123,11 +123,14 @@ celerybeat.pid
|
||||||
*.sage.py
|
*.sage.py
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
ENV/
|
ENV/
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.production
|
||||||
|
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
|
|
||||||
|
|
@ -163,3 +166,7 @@ cython_debug/
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
pyrightconfig.json
|
pyrightconfig.json
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
|
|
||||||
86
CLAUDE.md
Normal file
86
CLAUDE.md
Normal file
|
|
@ -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.
|
||||||
|
|
@ -19,6 +19,7 @@ $table("EXERCISE", "exercise"){
|
||||||
$column("NAME") VARCHAR
|
$column("NAME") VARCHAR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$table("APPROACH", "approach"){
|
$table("APPROACH", "approach"){
|
||||||
$pk("ID") INTEGER NOT NULL
|
$pk("ID") INTEGER NOT NULL
|
||||||
$fk("EXERCISE") INTEGER NOT NULL
|
$fk("EXERCISE") INTEGER NOT NULL
|
||||||
|
|
|
||||||
25
DOCS/deployment.puml
Normal file
25
DOCS/deployment.puml
Normal file
|
|
@ -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
|
||||||
|
|
@ -1,11 +1,62 @@
|
||||||
|
from datetime import datetime
|
||||||
|
import logging
|
||||||
from fastapi import APIRouter
|
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
|
from app.core.parsers.obsidian import parse_training_data
|
||||||
|
|
||||||
|
|
||||||
|
sqllite_executor = SQLiteExecutor()
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/obsidian/")
|
@router.get("/obsidian/")
|
||||||
async def obsidian_trainings_list():
|
async def obsidian_trainings_list():
|
||||||
return {
|
return {"data": parse_training_data()}
|
||||||
"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"}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,38 @@
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
app_name: str = "Fitness Parser API"
|
# Base app settings
|
||||||
version: str = "0.1.0"
|
model_config = SettingsConfigDict(env_file=".env")
|
||||||
|
app_name: str = "F1tness Parser API"
|
||||||
|
version: str = "0.0.1"
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
|
|
||||||
class Config:
|
# SQLite database settings
|
||||||
env_file = ".env"
|
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()
|
settings = Settings()
|
||||||
36
app/core/database/connection.py
Normal file
36
app/core/database/connection.py
Normal file
|
|
@ -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
|
||||||
0
app/core/database/models/__init__.py
Normal file
0
app/core/database/models/__init__.py
Normal file
26
app/core/database/models/approach.py
Normal file
26
app/core/database/models/approach.py
Normal file
|
|
@ -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
|
||||||
26
app/core/database/models/exercise.py
Normal file
26
app/core/database/models/exercise.py
Normal file
|
|
@ -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
|
||||||
26
app/core/database/models/training.py
Normal file
26
app/core/database/models/training.py
Normal file
|
|
@ -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
|
||||||
0
app/core/dto/__init__.py
Normal file
0
app/core/dto/__init__.py
Normal file
25
app/core/dto/training.py
Normal file
25
app/core/dto/training.py
Normal file
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -2,7 +2,7 @@ import re
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from datetime import datetime
|
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.apple_mapper import unique_apple_exercises_mapper
|
||||||
from app.core.parsers.base import BaseNotesParser
|
from app.core.parsers.base import BaseNotesParser
|
||||||
|
|
||||||
|
|
@ -47,18 +47,18 @@ class AppleNotesParser(BaseNotesParser):
|
||||||
return True, date, trainer, year_count
|
return True, date, trainer, year_count
|
||||||
return False, "", "", ""
|
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."""
|
"""Create Training object from date string with fallback parsing."""
|
||||||
try:
|
try:
|
||||||
return Training(
|
return TrainingDTO(
|
||||||
date=datetime.strptime(date_str, "%d.%m.%Y").date(), exercises=[]
|
date=datetime.strptime(date_str, "%d.%m.%Y").date(), exercises=[]
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return Training(
|
return TrainingDTO(
|
||||||
date=datetime.strptime(date_str, "%d.%m.%y").date(), exercises=[]
|
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."""
|
"""Parse Apple Notes training data from string input."""
|
||||||
# Override the data file reading with direct string input
|
# Override the data file reading with direct string input
|
||||||
original_method = self.read_data_file
|
original_method = self.read_data_file
|
||||||
|
|
@ -72,13 +72,13 @@ class AppleNotesParser(BaseNotesParser):
|
||||||
self.read_data_file = original_method
|
self.read_data_file = original_method
|
||||||
|
|
||||||
|
|
||||||
def parse_training_data() -> List[Training]:
|
def parse_training_data() -> List[TrainingDTO]:
|
||||||
"""Parse Apple Notes training data."""
|
"""Parse Apple Notes training data."""
|
||||||
parser = AppleNotesParser()
|
parser = AppleNotesParser()
|
||||||
return parser.parse_training_data()
|
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())."""
|
"""Remap exercise names using Apple-specific mapping (deprecated - use parser.parse_and_map_training_data())."""
|
||||||
parser = AppleNotesParser()
|
parser = AppleNotesParser()
|
||||||
return parser.apply_exercise_mapping(apple_trainings)
|
return parser.apply_exercise_mapping(apple_trainings)
|
||||||
|
|
@ -1,9 +1,79 @@
|
||||||
|
list_of_unique_apple_names = [
|
||||||
|
"Тяга горизонтального блока",
|
||||||
|
"Тяга горизонтального блока (по очереди)",
|
||||||
|
"Тяга гантелей в наклоне (по очереди)",
|
||||||
|
"Тяга гантелей на скамье",
|
||||||
|
"Тяга вертикального блока",
|
||||||
|
"Тяга вертикального блока (обратный хват)",
|
||||||
|
"Разгибание рук сидя (трицепс машина)",
|
||||||
|
"Подъем штанги на бицепс стоя",
|
||||||
|
"Подъем гантелей на бицепс стоя",
|
||||||
|
"Сгибание ног сидя",
|
||||||
|
"Сгибание ног лежа",
|
||||||
|
"Сведение рук в пек-дек",
|
||||||
|
"Румынская тяга",
|
||||||
|
"Разгибание ног сидя",
|
||||||
|
"Махи гантелей стоя",
|
||||||
|
"Разведение рук в стороны в наклоне (гантели)",
|
||||||
|
"Приседания",
|
||||||
|
"Подъем ног на турнике",
|
||||||
|
"Подтягивания",
|
||||||
|
"Подтягивания обратным хватом",
|
||||||
|
"Отжимания",
|
||||||
|
"Отведение рук в кроссовере (по очереди)",
|
||||||
|
"Разведение рук в пек-дек (по очереди)",
|
||||||
|
"Разведение рук в пек-дек",
|
||||||
|
"Отжимание на трицепс в кроссовере",
|
||||||
|
"Баттерфляй",
|
||||||
|
"Болгарские сплит-приседания",
|
||||||
|
"Брусья",
|
||||||
|
"Вертикальная тяга одной рукой",
|
||||||
|
"Выпады",
|
||||||
|
"Гиперэкстензия",
|
||||||
|
"Гравитрон",
|
||||||
|
"Гребная тяга с упором в грудь (по очереди)",
|
||||||
|
"Разведение рук в стороны (дельт-машина)",
|
||||||
|
"Жим гантелей лежа",
|
||||||
|
"Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
|
"Жим гантелей сидя",
|
||||||
|
"Жим ногами",
|
||||||
|
"Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от плеч вверх в тренажере (рычаги)",
|
||||||
|
"Икроножные сидя",
|
||||||
|
"Пресс на наклонной скамье",
|
||||||
|
"Бицепс машина",
|
||||||
|
"Pull down",
|
||||||
|
"Тяга Т-грифа",
|
||||||
|
"Французский жим гантели сидя",
|
||||||
|
"Молоты стоя (наискосок)",
|
||||||
|
"Отведение руки из-за спины в кроссовере",
|
||||||
|
"Гребная тяга с упором в грудь",
|
||||||
|
"Тяга штанги в наклоне",
|
||||||
|
"Молоты стоя",
|
||||||
|
"Жим штанги лежа",
|
||||||
|
"Тяга штанги в наклоне (обратным хватом)",
|
||||||
|
"Жим штанги сидя (45 градусов)",
|
||||||
|
"Наклоны с прямой спиной",
|
||||||
|
"Разгибание рук в наклоне (кик-бек)",
|
||||||
|
"Разгибание спины",
|
||||||
|
"Скручивания",
|
||||||
|
"Подъем гантелей на бицепс сидя"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
unique_apple_exercises_mapper = {
|
unique_apple_exercises_mapper = {
|
||||||
|
# Баттерфляй
|
||||||
"Батерфляй": "Баттерфляй",
|
"Батерфляй": "Баттерфляй",
|
||||||
"Баттерфляй": "Баттерфляй",
|
"Баттерфляй": "Баттерфляй",
|
||||||
"Баттерфляй дю": "Баттерфляй",
|
"Баттерфляй дю": "Баттерфляй",
|
||||||
|
|
||||||
|
# Подъем гантелей на бицепс сидя
|
||||||
"Бицепс на лавке 45⁰": "Подъем гантелей на бицепс сидя",
|
"Бицепс на лавке 45⁰": "Подъем гантелей на бицепс сидя",
|
||||||
"Болгарский присед": "Болгарские сплит-приседения",
|
|
||||||
|
# Болгарские сплит-приседания
|
||||||
|
"Болгарский присед": "Болгарские сплит-приседания",
|
||||||
|
|
||||||
|
# Брусья
|
||||||
"Брусья": "Брусья",
|
"Брусья": "Брусья",
|
||||||
"Брусья (гравитрон)": "Брусья",
|
"Брусья (гравитрон)": "Брусья",
|
||||||
"Брусья в тренажере": "Брусья",
|
"Брусья в тренажере": "Брусья",
|
||||||
|
|
@ -12,42 +82,48 @@ unique_apple_exercises_mapper = {
|
||||||
"Брусья узким хватом за": "Брусья",
|
"Брусья узким хватом за": "Брусья",
|
||||||
"Брусья широким хватом": "Брусья",
|
"Брусья широким хватом": "Брусья",
|
||||||
"Брусья-прямые ноги": "Брусья",
|
"Брусья-прямые ноги": "Брусья",
|
||||||
"ГАК машина": "Жим ногами (гакк-машина)",
|
"Отжимания на брусьях": "Брусья",
|
||||||
"Гакк машина": "Жим ногами (гакк-машина)",
|
"Отжимания на брусьях узким хватом": "Брусья",
|
||||||
"Гакк присед": "Жим ногами (гакк-машина)",
|
"Отжимания на брусьях широким хватом": "Брусья",
|
||||||
"Гантели": "Подъем гантелей на бицепс стоя",
|
|
||||||
"Гантели к поясу лежа на скамье": "Тяга гантелей на скамье",
|
# Выпады
|
||||||
"Гантели молот": "Гантели молот",
|
"Присд на одну ногу (по очереди)": "Выпады",
|
||||||
"Гантели на лавках": "Жим гантелей сидя",
|
"Присед на одну ногу": "Выпады",
|
||||||
"Гантели-молот": "Гантели молот",
|
"Присед на одну ногу (каждая)": "Выпады",
|
||||||
|
"Приседания на одной ноге": "Выпады",
|
||||||
|
|
||||||
|
# Молоты стоя
|
||||||
|
"Гантели молот": "Молоты стоя",
|
||||||
|
"Гантели-молот": "Молоты стоя",
|
||||||
|
"Молот назад двумя руками": "Молоты стоя",
|
||||||
|
"Молот трицепс стоя": "Молоты стоя",
|
||||||
|
"Молоты": "Молоты стоя",
|
||||||
|
"Сгибание гантелей в стиле молот одновременно": "Молоты стоя",
|
||||||
|
|
||||||
|
# Гиперэкстензия
|
||||||
"Гипекстензия": "Гиперэкстензия",
|
"Гипекстензия": "Гиперэкстензия",
|
||||||
"Гиперэкстензия": "Гиперэкстензия",
|
"Гиперэкстензия": "Гиперэкстензия",
|
||||||
"Горизонтальна тяга на себя": "Тяга горизонтального блока",
|
|
||||||
"Горизонтальная тяга блока": "Тяга горизонтального блока",
|
# Гравитрон
|
||||||
"Гравитрон": "Гравитрон",
|
|
||||||
"Гравитрор": "Гравитрон",
|
"Гравитрор": "Гравитрон",
|
||||||
|
|
||||||
|
# Гребная тяга с упором в грудь
|
||||||
"Гребная тяга": "Гребная тяга с упором в грудь",
|
"Гребная тяга": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь",
|
"Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга с упором в грудь как": "Гребная тяга с упором в грудь",
|
"Гребная тяга с упором в грудь как": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга с упором на грудь": "Гребная тяга с упором в грудь",
|
"Гребная тяга с упором на грудь": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга сидя (одна рука)": "Гребная тяга с упором в грудь (по очереди)",
|
|
||||||
"Гребная тяга сидя одной рукой": "Гребная тяга с упором в грудь (по очереди)",
|
|
||||||
"Гребная тяга сидя с упором в грудт": "Гребная тяга с упором в грудь",
|
"Гребная тяга сидя с упором в грудт": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга сидя с упором в грудь": "Гребная тяга с упором в грудь",
|
"Гребная тяга сидя с упором в грудь": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга сидя с упором в грудь (одной рукой рычаг)": "Гребная тяга с упором в грудь (по очереди)",
|
|
||||||
"Гребная тяга\xa0 упором в грудьс": "Гребная тяга с упором в грудь",
|
"Гребная тяга\xa0 упором в грудьс": "Гребная тяга с упором в грудь",
|
||||||
"Жим в тренажере вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
"Тяга на себя с упором в грудь": "Гребная тяга с упором в грудь",
|
||||||
"Жим в тренажере на плечи блочный (3х12)": "Жим от плеч вверх в тренажере (рычаги)",
|
|
||||||
"Жим в тренажёре на плечи (силовой тренажёр: жим сидя)": "Жим от плеч вверх в тренажере (рычаги)",
|
# Гребная тяга с упором в грудь (по очереди)
|
||||||
"Жим вверх 80⁰": "Жим гантелей сидя",
|
"Гребная тяга сидя (одна рука)": "Гребная тяга с упором в грудь (по очереди)",
|
||||||
|
"Гребная тяга сидя одной рукой": "Гребная тяга с упором в грудь (по очереди)",
|
||||||
|
"Гребная тяга сидя с упором в грудь (одной рукой рычаг)": "Гребная тяга с упором в грудь (по очереди)",
|
||||||
|
|
||||||
|
# Жим гантелей лежа
|
||||||
"Жим гантелей": "Жим гантелей лежа",
|
"Жим гантелей": "Жим гантелей лежа",
|
||||||
"Жим гантелей 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
|
||||||
"Жим гантелей 60⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
|
||||||
"Жим гантелей 80⁰": "Жим гантелей сидя",
|
|
||||||
"Жим гантелей 90⁰": "Жим гантелей сидя",
|
|
||||||
"Жим гантелей вверх 80⁰": "Жим гантелей сидя",
|
|
||||||
"Жим гантелей вверх 90⁰": "Жим гантелей сидя",
|
|
||||||
"Жим гантелей вверх сидя 90⁰": "Жим гантелей сидя",
|
|
||||||
"Жим гантелей лежа": "Жим гантелей лежа",
|
"Жим гантелей лежа": "Жим гантелей лежа",
|
||||||
"Жим гантелей лежа 15⁰": "Жим гантелей лежа",
|
"Жим гантелей лежа 15⁰": "Жим гантелей лежа",
|
||||||
"Жим гантелей лежа 30⁰": "Жим гантелей лежа",
|
"Жим гантелей лежа 30⁰": "Жим гантелей лежа",
|
||||||
|
|
@ -55,37 +131,64 @@ unique_apple_exercises_mapper = {
|
||||||
"Жим гантелей лёжа": "Жим гантелей лежа",
|
"Жим гантелей лёжа": "Жим гантелей лежа",
|
||||||
"Жим гантелей лёжа на скамье": "Жим гантелей лежа",
|
"Жим гантелей лёжа на скамье": "Жим гантелей лежа",
|
||||||
"Жим гантелей на скамье": "Жим гантелей лежа",
|
"Жим гантелей на скамье": "Жим гантелей лежа",
|
||||||
|
"Жис гантелей лежа": "Жим гантелей лежа",
|
||||||
|
|
||||||
|
# Жим гантелей лежа (Под углом 45 градусов)
|
||||||
|
"Жим гантелей 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
|
"Жим гантелей 60⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
"Жим гантелей на скамье 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
"Жим гантелей на скамье 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
|
"Жим сидя 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
|
|
||||||
|
# Жим гантелей сидя
|
||||||
|
"Жим гантелей 80⁰": "Жим гантелей сидя",
|
||||||
|
"Жим гантелей 90⁰": "Жим гантелей сидя",
|
||||||
|
"Жим гантелей вверх 80⁰": "Жим гантелей сидя",
|
||||||
|
"Жим гантелей вверх 90⁰": "Жим гантелей сидя",
|
||||||
|
"Жим гантелей вверх сидя 90⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя": "Жим гантелей сидя",
|
"Жим гантелей сидя": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 80⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 80⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 90⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 90⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя на скамейке": "Жим гантелей сидя",
|
"Жим гантелей сидя на скамейке": "Жим гантелей сидя",
|
||||||
"Жим гантелей стоя": "Подъем гантелей на бицепс стоя",
|
"Жим вверх 80⁰": "Жим гантелей сидя",
|
||||||
"Жим л груди в тренажёре": "Жим от груди сидя в тренажере (рычаги)",
|
"Жим от плеч вверх сидя 80⁰": "Жим гантелей сидя",
|
||||||
"Жим лежа": "Жим штанги лежа",
|
"Гантели на лавках": "Жим гантелей сидя",
|
||||||
|
|
||||||
|
# ГАК машина
|
||||||
|
"ГАК машина": "ГАК машина",
|
||||||
|
"Гакк машина": "ГАК машина",
|
||||||
|
"Гакк присед": "ГАК машина",
|
||||||
|
|
||||||
|
# Жим ногами
|
||||||
"Жим ногами": "Жим ногами",
|
"Жим ногами": "Жим ногами",
|
||||||
"Жим ногами (3х15)": "Жим ногами",
|
"Жим ногами (3х15)": "Жим ногами",
|
||||||
"Жим ногами (медленно вниз)": "Жим ногами",
|
"Жим ногами (медленно вниз)": "Жим ногами",
|
||||||
"Жим ногами лежа": "Жим ногами",
|
"Жим ногами лежа": "Жим ногами",
|
||||||
"Жим ногами медленно": "Жим ногами",
|
"Жим ногами медленно": "Жим ногами",
|
||||||
"Жим от груди": "Жим штанги лежа",
|
|
||||||
"Жим от груди (сидя, тренажёр)": "Жим от груди сидя в тренажере (блоки)",
|
# Жим от груди сидя в тренажере (рычаги)
|
||||||
"Жим от груди в тренажере сидя": "Жим от груди сидя в тренажере (блоки)",
|
"Жим л груди в тренажёре": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
"Жим от груди в тренажёре (кирпичики)": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя (блинчики)": "Жим от груди сидя в тренажере (рычаги)",
|
"Жим от груди сидя (блинчики)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
"Жим от груди сидя в тренажере": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя в тренажере (около трицепс машины)": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя в тренажере (рычаги)": "Жим от груди сидя в тренажере (рычаги)",
|
"Жим от груди сидя в тренажере (рычаги)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
"Жим от груди сидя в тренажере рычаги": "Жим от груди сидя в тренажере (рычаги)",
|
"Жим от груди сидя в тренажере рычаги": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
"Жим от груди сидя в тренажёре": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя в тренажёре (блинчики)": "Жим от груди сидя в тренажере (блоки)",
|
|
||||||
"Жим от груди сидя в тренажёре (рычаги)": "Жим от груди сидя в тренажере (рычаги)",
|
"Жим от груди сидя в тренажёре (рычаги)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жис сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди (сидя, тренажёр)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди в тренажере сидя": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди сидя": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди сидя в тренажере": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди сидя в тренажере (около трицепс машины)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди сидя в тренажёре": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Жим от груди сидя в тренажёре (блинчики)": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
"Силовой тренажер": "Жим от груди сидя в тренажере (рычаги)",
|
||||||
|
|
||||||
|
# Жим от плеч вверх в тренажере (рычаги)
|
||||||
|
"Жим в тренажере вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
|
"Жим в тренажере на плечи блочный (3х12)": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
|
"Жим в тренажёре на плечи (силовой тренажёр: жим сидя)": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч (рычаги)": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч (рычаги)": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч вверх в тренажёре": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч вверх в тренажёре": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч вверх сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч вверх сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч вверх сидя 80⁰": "Жим гантелей сидя",
|
|
||||||
"Жим от плеч вверх сидя в тренажере": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч вверх сидя в тренажере": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плеч сидя (рычаги)": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч сидя (рычаги)": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
|
|
@ -93,32 +196,31 @@ unique_apple_exercises_mapper = {
|
||||||
"Жим от плеч сидя хз": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч сидя хз": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим от плечей вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плечей вверх": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим плечами вверх сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
"Жим плечами вверх сидя": "Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Жим сидя 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
|
||||||
"Жим штанги 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)": "Разгибание ног сидя",
|
"Разгибание ног сидя (4х10)": "Разгибание ног сидя",
|
||||||
"Разгибание прямых рук сидя": "Разведение рук в стороны (дельт-машина)",
|
|
||||||
"Разгибание рук в кроссовере": "Отжимание на трицепс в кроссовере",
|
# Разгибание рук в наклоне (кик-бек)
|
||||||
"Разгибание рук в тренажёре для трицепса": "Отжимание на трицепс в кроссовере",
|
"Разгибание кик-бек": "Разгибание рук в наклоне (кик-бек)",
|
||||||
"Разгибание рук в трицепс машине (3х10)": "Отжимание на трицепс в кроссовере",
|
|
||||||
|
# Разгибание рук сидя (трицепс машина)
|
||||||
"Разгибание рук сидя": "Разгибание рук сидя (трицепс машина)",
|
"Разгибание рук сидя": "Разгибание рук сидя (трицепс машина)",
|
||||||
"Разгибание рук сидя (локти в стороны)": "Разгибание рук сидя (трицепс машина)",
|
"Разгибание рук сидя (локти в стороны)": "Разгибание рук сидя (трицепс машина)",
|
||||||
"Разгибание рук сидя (трицепс машина)": "Разгибание рук сидя (трицепс машина)",
|
"Разгибание рук сидя (трицепс машина)": "Разгибание рук сидя (трицепс машина)",
|
||||||
"Разгибание рук стоя с канатом": "Отжимание на трицепс в кроссовере",
|
"Трицепс машина": "Разгибание рук сидя (трицепс машина)",
|
||||||
"Разгибание спины": "Разгибание спины",
|
"Трицепс сидя": "Разгибание рук сидя (трицепс машина)",
|
||||||
|
"Трицепс-машина (разгибание рук сидя)": "Разгибание рук сидя (трицепс машина)",
|
||||||
|
|
||||||
|
# Румынская тяга
|
||||||
"Румынская тяга": "Румынская тяга",
|
"Румынская тяга": "Румынская тяга",
|
||||||
"Румынская тяга с гантелями": "Румынская тяга",
|
"Румынская тяга с гантелями": "Румынская тяга",
|
||||||
"Румынская тяна": "Румынская тяга",
|
"Румынская тяна": "Румынская тяга",
|
||||||
"Румынская тяоа": "Румынская тяга",
|
"Румынская тяоа": "Румынская тяга",
|
||||||
"Сведение на скамейке":"Разведение рук в стороны в наклоне (гантели)",
|
|
||||||
|
# Сведение рук в пек-дек
|
||||||
"Сведение рук в пек дек": "Сведение рук в пек-дек",
|
"Сведение рук в пек дек": "Сведение рук в пек-дек",
|
||||||
"Сведение рук в пек дек зэ": "Сведение рук в пек-дек",
|
"Сведение рук в пек дек зэ": "Сведение рук в пек-дек",
|
||||||
"Сведение рук в тренажере": "Сведение рук в пек-дек",
|
"Сведение рук в тренажере": "Сведение рук в пек-дек",
|
||||||
|
|
@ -206,37 +340,39 @@ unique_apple_exercises_mapper = {
|
||||||
"Сведение рук сидя": "Сведение рук в пек-дек",
|
"Сведение рук сидя": "Сведение рук в пек-дек",
|
||||||
"Сведение рук сидя пек дек": "Сведение рук в пек-дек",
|
"Сведение рук сидя пек дек": "Сведение рук в пек-дек",
|
||||||
"Сведения рук пек дек": "Сведение рук в пек-дек",
|
"Сведения рук пек дек": "Сведение рук в пек-дек",
|
||||||
"Сгибание гантелей в стиле молот одновременно": "Гантели молот",
|
|
||||||
"Сгибание ног": "Сгибание ног сидя",
|
# Сгибание ног лежа
|
||||||
"Сгибание ног лежа": "Сгибание ног лежа",
|
"Сгибание ног лежа": "Сгибание ног лежа",
|
||||||
"Сгибание ног лежа (медленно разгибать)": "Сгибание ног лежа",
|
"Сгибание ног лежа (медленно разгибать)": "Сгибание ног лежа",
|
||||||
"Сгибание ног лёжа": "Сгибание ног лежа",
|
"Сгибание ног лёжа": "Сгибание ног лежа",
|
||||||
|
"Сгибания ног лежа": "Сгибание ног лежа",
|
||||||
|
|
||||||
|
# Сгибание ног сидя
|
||||||
|
"Сгибание ног": "Сгибание ног сидя",
|
||||||
"Сгибание ног сидя": "Сгибание ног сидя",
|
"Сгибание ног сидя": "Сгибание ног сидя",
|
||||||
"Сгибание ног сидя (3х12)": "Сгибание ног сидя",
|
"Сгибание ног сидя (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,
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
from typing import List, Tuple, Dict, Optional
|
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
|
from app.core.utils.date_refactor import parse_training_date
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ class BaseNotesParser:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
return content
|
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."""
|
"""Convert raw exercise data into Exercise object with approaches."""
|
||||||
reps_list: List[int] = [int(rep) for rep in reps.split("-")]
|
reps_list: List[int] = [int(rep) for rep in reps.split("-")]
|
||||||
weight_splitted: bool = False
|
weight_splitted: bool = False
|
||||||
|
|
@ -45,24 +45,24 @@ class BaseNotesParser:
|
||||||
approaches = []
|
approaches = []
|
||||||
if not weight:
|
if not weight:
|
||||||
for rep_index in range(0, len(reps_list)):
|
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)
|
approaches.append(approach)
|
||||||
else:
|
else:
|
||||||
weight_pointer = 0
|
weight_pointer = 0
|
||||||
for rep_index in range(0, len(reps_list)):
|
for rep_index in range(0, len(reps_list)):
|
||||||
approach = Approach(
|
approach = ApproachDTO(
|
||||||
weight=weight_list[weight_pointer], reps=reps_list[rep_index]
|
weight=weight_list[weight_pointer], reps=reps_list[rep_index]
|
||||||
)
|
)
|
||||||
if rep_index < len(weight_list) - 1:
|
if rep_index < len(weight_list) - 1:
|
||||||
weight_pointer += 1
|
weight_pointer += 1
|
||||||
approaches.append(approach)
|
approaches.append(approach)
|
||||||
|
|
||||||
exercise = Exercise(
|
exercise = ExerciseDTO(
|
||||||
name=name, approaches=approaches, splitted_weight=weight_splitted
|
name=name, approaches=approaches, splitted_weight=weight_splitted
|
||||||
)
|
)
|
||||||
return exercise
|
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."""
|
"""Parse exercise data from a table row."""
|
||||||
stripped: List[str] = [entry.strip() for entry in exercise_line.split("|")][
|
stripped: List[str] = [entry.strip() for entry in exercise_line.split("|")][
|
||||||
1:-1
|
1:-1
|
||||||
|
|
@ -90,11 +90,11 @@ class BaseNotesParser:
|
||||||
"""Parse training header. Override in subclasses for specific formats."""
|
"""Parse training header. Override in subclasses for specific formats."""
|
||||||
raise NotImplementedError("Subclasses must implement parse_training_header")
|
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."""
|
"""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."""
|
"""Main parsing method. Override for specific parsing logic."""
|
||||||
training_data = self.filter_training_data(
|
training_data = self.filter_training_data(
|
||||||
self.read_data_file(self.data_file_name)
|
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]
|
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."""
|
"""Apply exercise name mapping to all trainings."""
|
||||||
for training in trainings:
|
for training in trainings:
|
||||||
if not training or not training.exercises:
|
if not training or not training.exercises:
|
||||||
|
|
@ -133,7 +133,7 @@ class BaseNotesParser:
|
||||||
exercise.name = mapped_name
|
exercise.name = mapped_name
|
||||||
return trainings
|
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."""
|
"""Parse training data and apply exercise mapping."""
|
||||||
trainings = self.parse_training_data()
|
trainings = self.parse_training_data()
|
||||||
return self.apply_exercise_mapping(trainings)
|
return self.apply_exercise_mapping(trainings)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import re
|
import re
|
||||||
from typing import List, Tuple
|
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.obsidian_mapper import obsidian_unique_exercies_mapping
|
||||||
from app.core.parsers.base import BaseNotesParser
|
from app.core.parsers.base import BaseNotesParser
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ class ObsidianNotesParser(BaseNotesParser):
|
||||||
return True, date, trainer, year_count
|
return True, date, trainer, year_count
|
||||||
return False, "", "", ""
|
return False, "", "", ""
|
||||||
|
|
||||||
def parse(self, data: str) -> List[Training]:
|
def parse(self, data: str) -> List[TrainingDTO]:
|
||||||
"""Parse Obsidian training data from string input."""
|
"""Parse Obsidian training data from string input."""
|
||||||
# Override the data file reading with direct string input
|
# Override the data file reading with direct string input
|
||||||
original_method = self.read_data_file
|
original_method = self.read_data_file
|
||||||
|
|
@ -49,13 +49,13 @@ class ObsidianNotesParser(BaseNotesParser):
|
||||||
self.read_data_file = original_method
|
self.read_data_file = original_method
|
||||||
|
|
||||||
|
|
||||||
def parse_training_data() -> List[Training]:
|
def parse_training_data() -> List[TrainingDTO]:
|
||||||
"""Parse Obsidian Notes training data."""
|
"""Parse Obsidian Notes training data."""
|
||||||
parser = ObsidianNotesParser()
|
parser = ObsidianNotesParser()
|
||||||
return parser.parse_training_data()
|
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())."""
|
"""Remap exercise names using Obsidian-specific mapping (deprecated - use parser.parse_and_map_training_data())."""
|
||||||
parser = ObsidianNotesParser()
|
parser = ObsidianNotesParser()
|
||||||
return parser.apply_exercise_mapping(obsidian_trainings)
|
return parser.apply_exercise_mapping(obsidian_trainings)
|
||||||
|
|
|
||||||
|
|
@ -40,124 +40,335 @@ list_of_unique_names = [
|
||||||
"Жим от груди сидя в тренажере (рычаги)",
|
"Жим от груди сидя в тренажере (рычаги)",
|
||||||
"Жим от плеч вверх в тренажере (рычаги)",
|
"Жим от плеч вверх в тренажере (рычаги)",
|
||||||
"Икроножные сидя",
|
"Икроножные сидя",
|
||||||
"Пресс на наклонной скамье"
|
"Пресс на наклонной скамье",
|
||||||
|
"Бицепс машина",
|
||||||
|
"Pull down (блины)",
|
||||||
|
"Pull down",
|
||||||
|
"Тяга Т-грифа",
|
||||||
|
"Французский жим гантели сидя",
|
||||||
|
"Молоты стоя (наискосок)",
|
||||||
|
"Отведение руки из-за спины в кроссовере",
|
||||||
|
"Гребная тяга с упором в грудь",
|
||||||
|
"Тяга штанги в наклоне",
|
||||||
|
"Молоты с гантелями лёжа",
|
||||||
|
"Махи гантелей стоя",
|
||||||
|
"Жим штанги лежа",
|
||||||
|
"Подъем штанги стоя",
|
||||||
|
"Подъем гантелей на предплечья обратным хватом",
|
||||||
|
"Жим от плеч вверх в тренажёре (блины)",
|
||||||
|
"Жим от плеч вверх в тренажёре (кирпичики)"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
obsidian_unique_exercies_mapping = {
|
obsidian_unique_exercies_mapping = {
|
||||||
|
# Подъем ног в висе
|
||||||
|
"Подьем ног в висе": "Подъем ног в висе",
|
||||||
|
"Подъем ног в висе": "Подъем ног в висе",
|
||||||
|
"Подъём ног в висе": "Подъем ног в висе",
|
||||||
|
|
||||||
|
# Подъем штанги стоя
|
||||||
|
"Подъем штанги на бицепс стоя": "Подъем штанги стоя",
|
||||||
|
"Подьем штанги на бицепс": "Подъем штанги стоя",
|
||||||
|
"Подъём штанги стоя": "Подъем штанги стоя",
|
||||||
|
"Подьем штанги стоя": "Подъем штанги стоя",
|
||||||
|
"Разведение рук в стороны с гантелями стоя": "Подъем штанги стоя",
|
||||||
|
"Сгибание штанги стоя на бицепс": "Подъем штанги стоя",
|
||||||
|
|
||||||
|
|
||||||
|
# Подъем гантелей на предплечья обратным хватом
|
||||||
|
'Подъем гантелей на предплечье обратным хватом': 'Подъем гантелей на предплечья обратным хватом',
|
||||||
|
'Подъем гартелей на предплечье обратным хватом': 'Подъем гантелей на предплечья обратным хватом',
|
||||||
|
|
||||||
|
# Баттерфляй
|
||||||
"Баттерфляй": "Баттерфляй",
|
"Баттерфляй": "Баттерфляй",
|
||||||
|
|
||||||
|
# Бицепс машина
|
||||||
|
"Бицепс-машина": "Бицепс машина",
|
||||||
|
"Бицепс в тренажёре": "Бицепс машина",
|
||||||
|
"Бицепс в тренажёре (arm curl)": "Бицепс машина",
|
||||||
|
|
||||||
|
# Болгарские сплит-приседания
|
||||||
"Болгарские приседания на одну ногу": "Болгарские сплит-приседения",
|
"Болгарские приседания на одну ногу": "Болгарские сплит-приседения",
|
||||||
|
|
||||||
|
# Брусья
|
||||||
"Брусья": "Брусья",
|
"Брусья": "Брусья",
|
||||||
"Брусья узким хватом": "Брусья",
|
"Брусья узким хватом": "Брусья",
|
||||||
|
|
||||||
|
# Вертикальная тяга одной рукой
|
||||||
"Вертикальная тяга одной рукой 45⁰": "Вертикальная тяга одной рукой",
|
"Вертикальная тяга одной рукой 45⁰": "Вертикальная тяга одной рукой",
|
||||||
|
|
||||||
|
# Выпады
|
||||||
"Выпады вперед по очереди каждой ногой": "Выпады",
|
"Выпады вперед по очереди каждой ногой": "Выпады",
|
||||||
"Выпады с гантелями на одну ногу вперед": "Выпады",
|
"Выпады с гантелями на одну ногу вперед": "Выпады",
|
||||||
|
"Выпады вперед с гантелями на одну ногу": "Выпады",
|
||||||
|
|
||||||
|
# Гиперэкстензия
|
||||||
"Гиперэкстензия": "Гиперэкстензия",
|
"Гиперэкстензия": "Гиперэкстензия",
|
||||||
|
|
||||||
|
# Гравитрон
|
||||||
"Гравитрон": "Гравитрон",
|
"Гравитрон": "Гравитрон",
|
||||||
"Гравитрон (медленно вниз)": "Гравитрон",
|
"Гравитрон (медленно вниз)": "Гравитрон",
|
||||||
|
|
||||||
|
# Гребная тяга с упором в грудь
|
||||||
"Гребная тяга с упорм в грудь": "Гребная тяга с упором в грудь",
|
"Гребная тяга с упорм в грудь": "Гребная тяга с упором в грудь",
|
||||||
"Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь",
|
"Гребная тяга с упором в грудь": "Гребная тяга с упором в грудь",
|
||||||
|
|
||||||
|
# Гребная тяга с упором в грудь (по очереди)
|
||||||
"Гребная тяга с упором в грудь (одна рука)": "Гребная тяга с упором в грудь (по очереди)",
|
"Гребная тяга с упором в грудь (одна рука)": "Гребная тяга с упором в грудь (по очереди)",
|
||||||
"Дельт машина": "Разведение рук в стороны (дельт-машина)",
|
|
||||||
"Дельт машина (разведение рук в стороны)": "Разведение рук в стороны (дельт-машина)",
|
# Жим гантелей лежа
|
||||||
"Жим гантелей лежа": "Жим гантелей лежа",
|
"Жим гантелей лежа": "Жим гантелей лежа",
|
||||||
"Жим гантелей лежа на скамье": "Жим гантелей лежа",
|
"Жим гантелей лежа на скамье": "Жим гантелей лежа",
|
||||||
"Жим гантелей лежа на скамье 30⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
|
||||||
"Жим гантелей лёжа": "Жим гантелей лежа",
|
"Жим гантелей лёжа": "Жим гантелей лежа",
|
||||||
|
"Жим гантелей от груди лежа": "Жим гантелей лежа",
|
||||||
|
"Жим от груди лежа с гантелями": "Жим гантелей лежа",
|
||||||
|
|
||||||
|
# Жим гантелей лежа (Под углом 45 градусов)
|
||||||
|
"Жим гантелей лежа на скамье 30⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
"Жим гантелей лёжа на скамейке 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
"Жим гантелей лёжа на скамейке 45⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
"Жим гантелей на скамье 65⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
"Жим гантелей на скамье 65⁰": "Жим гантелей лежа (Под углом 45 градусов)",
|
||||||
|
|
||||||
|
# Жим гантелей сидя
|
||||||
"Жим гантелей сидя": "Жим гантелей сидя",
|
"Жим гантелей сидя": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 80⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 80⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 85⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 85⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 8⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 8⁰": "Жим гантелей сидя",
|
||||||
"Жим гантелей сидя 90⁰": "Жим гантелей сидя",
|
"Жим гантелей сидя 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 рукой": "Тяга гантелей в наклоне (по очереди)",
|
"Тяга гантели в наклоне 1 рукой": "Тяга гантелей в наклоне (по очереди)",
|
||||||
"Тяга гантели в наклоне к поясу к стойки": "Тяга гантелей в наклоне (по очереди)",
|
"Тяга гантели в наклоне к поясу к стойки": "Тяга гантелей в наклоне (по очереди)",
|
||||||
"Тяга гантели в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)",
|
"Тяга гантели в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)",
|
||||||
"Тяга гантели в наклоне одной рукой (каждой)": "Тяга гантелей в наклоне (по очереди)",
|
"Тяга гантели в наклоне одной рукой (каждой)": "Тяга гантелей в наклоне (по очереди)",
|
||||||
|
"Тяга гантелей в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)",
|
||||||
|
"Тяга гантели к поясу в наклоне одной рукой": "Тяга гантелей в наклоне (по очереди)",
|
||||||
|
|
||||||
|
# Тяга гантелей на скамье
|
||||||
|
"Тяга гантелей к поясу лёжа на животе на скамье": "Тяга гантелей на скамье",
|
||||||
|
"Тяга гантелей лежа на животе на скамье 80°": "Тяга гантелей на скамье",
|
||||||
|
"Тяга гантелей на скамье": "Тяга гантелей на скамье",
|
||||||
"Тяга гантели лежа в наклоне на скамье": "Тяга гантелей на скамье",
|
"Тяга гантели лежа в наклоне на скамье": "Тяга гантелей на скамье",
|
||||||
"Тяга горизонтально блока одной рукой": "Тяга горизонтального блока (по очереди)",
|
"Тяга гантелей к поясу лежа на скамье": "Тяга гантелей на скамье",
|
||||||
|
|
||||||
|
# Тяга горизонтального блока
|
||||||
"Тяга горизонтального блока": "Тяга горизонтального блока",
|
"Тяга горизонтального блока": "Тяга горизонтального блока",
|
||||||
|
|
||||||
|
# Тяга горизонтального блока (по очереди)
|
||||||
|
"Тяга горизонтально блока одной рукой": "Тяга горизонтального блока (по очереди)",
|
||||||
"Тяга горизонтального блока 1 рукой поочерёдно": "Тяга горизонтального блока (по очереди)",
|
"Тяга горизонтального блока 1 рукой поочерёдно": "Тяга горизонтального блока (по очереди)",
|
||||||
"Тяга горизонтального блока одной рукой": "Тяга горизонтального блока (по очереди)",
|
"Тяга горизонтального блока одной рукой": "Тяга горизонтального блока (по очереди)",
|
||||||
"Пресс на скамье": "Пресс на наклонной скамье",
|
|
||||||
"Пресс на скамейке": "Пресс на наклонной скамье",
|
|
||||||
"Отжимания на трицепс":"Отжимания на трицепс в кроссовере",
|
|
||||||
"Молоты лежа":"Молоты с гантелями лёжа",
|
|
||||||
"Молоты лёжа":"Молоты с гантелями лёжа",
|
|
||||||
"Молоты с гантелями лежа":"Молоты с гантелями лёжа",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Тяга штанги в наклоне
|
||||||
|
"Тяга штанги к поясу в наклоне": "Тяга штанги в наклоне",
|
||||||
|
|
||||||
|
# Французский жим гантели сидя
|
||||||
|
'Французский жим с гантелей': 'Французский жим гантели сидя',
|
||||||
|
'Французский жим сидя': 'Французский жим гантели сидя',
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from app.core.parsers.apple import AppleNotesParser
|
from app.core.parsers.apple import AppleNotesParser
|
||||||
from app.core.parsers.obsidian import ObsidianNotesParser
|
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
|
"""Method for parsing all old data from apple and obsidian notes with exercise mapping applied
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
||||||
22
app/main.py
22
app/main.py
|
|
@ -1,13 +1,35 @@
|
||||||
|
import logging
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
||||||
from app.api.v1.api import api_router
|
from app.api.v1.api import api_router
|
||||||
from app.api.v1.web import web_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(
|
app = FastAPI(
|
||||||
title="Fitness Parser API",
|
title="Fitness Parser API",
|
||||||
description="API for parsing fitness training data from various sources",
|
description="API for parsing fitness training data from various sources",
|
||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
|
lifespan=lifespan,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||||
|
|
|
||||||
32
app/sandbox.py
Normal file
32
app/sandbox.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
from collections import defaultdict
|
||||||
|
from app.core.parsers.apple import AppleNotesParser
|
||||||
|
from app.core.parsers.obsidian import ObsidianNotesParser
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
|
||||||
|
om = ObsidianNotesParser()
|
||||||
|
obsidian_result = defaultdict(int)
|
||||||
|
o_mapped_trainings = om.parse_and_map_training_data()
|
||||||
|
for training in o_mapped_trainings:
|
||||||
|
for exercise in training.exercises:
|
||||||
|
obsidian_result[exercise.name] += 1
|
||||||
|
|
||||||
|
am = AppleNotesParser()
|
||||||
|
apple_result = defaultdict(int)
|
||||||
|
a_mapped_trainings = am.parse_and_map_training_data()
|
||||||
|
for training in a_mapped_trainings:
|
||||||
|
for exercise in training.exercises:
|
||||||
|
apple_result[exercise.name] += 1
|
||||||
|
|
||||||
|
print(f"apple trainings:\t{len(a_mapped_trainings)}")
|
||||||
|
print(f"osididian trainings:\t{len(o_mapped_trainings)}")
|
||||||
|
|
||||||
|
overall_trainings = a_mapped_trainings + o_mapped_trainings
|
||||||
|
print(f"overall trainings:\t{len(overall_trainings)}")
|
||||||
|
|
||||||
|
overall_result = defaultdict(int)
|
||||||
|
for training in overall_trainings:
|
||||||
|
for exercise in training.exercises:
|
||||||
|
overall_result[exercise.name] += 1
|
||||||
|
|
||||||
|
pprint(overall_result)
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-dark bg-primary">
|
<nav class="navbar navbar-dark bg-primary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<!-- TODO: find solution to not harcode links in hrefs -->
|
||||||
|
<a class="navbar-brand" href="/app/obsidian/list">
|
||||||
<strong>{{ app_name }}</strong>
|
<strong>{{ app_name }}</strong>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,10 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- DEBUG=true
|
- DEBUG=true
|
||||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/app --log-level debug
|
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/app --log-level debug
|
||||||
|
develop:
|
||||||
|
watch:
|
||||||
|
- action: sync
|
||||||
|
path: ./app
|
||||||
|
target: /app/app
|
||||||
|
- action: rebuild
|
||||||
|
path: ./pyproject.toml
|
||||||
|
|
|
||||||
35
compose.yaml
35
compose.yaml
|
|
@ -11,13 +11,32 @@ services:
|
||||||
- ./app:/app/app:ro
|
- ./app:/app/app:ro
|
||||||
- ./data:/app/data:ro
|
- ./data:/app/data:ro
|
||||||
- ./tests:/app/tests:ro
|
- ./tests:/app/tests:ro
|
||||||
|
- ./migrations:/app/migrations:ro
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- PYTHONPATH=/app
|
- PYTHONPATH=${PYTHONPATH}
|
||||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/app
|
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app/app
|
||||||
develop:
|
depends_on:
|
||||||
watch:
|
postgres:
|
||||||
- action: sync
|
condition: service_healthy
|
||||||
path: ./app
|
postgres:
|
||||||
target: /app/app
|
image: postgres:15-alpine
|
||||||
- action: rebuild
|
env_file:
|
||||||
path: ./pyproject.toml
|
- .env
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${POSTGRES_DATABASE_DB}
|
||||||
|
- POSTGRES_USER=${POSTGRES_DATABASE_USER}
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_DATABASE_PASSWORD}
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_DATABASE_PORT}:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_DATABASE_USER} -d ${POSTGRES_DATABASE_DB}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
|
||||||
158
data/obsidian.md
158
data/obsidian.md
|
|
@ -1,3 +1,161 @@
|
||||||
|
# 2025-10-09 (solo-107)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ---------------------------------------- | ----------- | ----------- |
|
||||||
|
| Подтягивания | | 10-7-6-5 |
|
||||||
|
| Тяга горизонтального блока | 60-65 | 12-12-12-12 |
|
||||||
|
| Жим от груди лежа с гантелями | 22.5х2-25х2 | 12-10-10-8 |
|
||||||
|
| Жим от груди сидя в тренажёре (блинчики) | 30х2 | 10-10-8-8 |
|
||||||
|
| Подъем ног в висе | | 12-10-10-8 |
|
||||||
|
|
||||||
|
# 2025-10-06 (solo-106)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ------ | ----------- |
|
||||||
|
| Подъем штанги стоя | 30 | 12-12-12-12 |
|
||||||
|
| Молоты стоя наискосок | 17.5х2 | 10-10-10-9 |
|
||||||
|
| Подъем гартелей на предплечье обратным хватом | 15х2 | 12-12-12-12 |
|
||||||
|
| Французский жим лежа со штангой | 25 | 12-12-12-12 |
|
||||||
|
| Жим от плеч вверх сидя в тренажёре (блинчики) | 40-45 | 12-10-10-10 |
|
||||||
|
|
||||||
|
# 2025-10-04 (solo-105)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ------------------------------------------------ | ----------- | -------------- |
|
||||||
|
| Подтягивания | | 8-7-6-6 |
|
||||||
|
| Тяга вертикального блока в тренажёре (кирпичики) | 80 | 12-12-12-12-11 |
|
||||||
|
| Сведение рук пек дек | 65-65-65-60 | 12-12-8-10 |
|
||||||
|
| Жим гантелей лежа | 22.5х2 | 12-10-10-8 |
|
||||||
|
| Пресс на скамье | | 12-12-12-12 |
|
||||||
|
# 2025-09-29 (solo-104)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ----------- | ----------- |
|
||||||
|
| Молоты стоя наискосок | 15х2-17.5х2 | 12-12-12-10 |
|
||||||
|
| Подъем гантелей на предплечье обратным хватом | 17.5х2 | 12-12-12-12 |
|
||||||
|
| Отдикна трицепс в кроссовере | 60 | 12-12-12-10 |
|
||||||
|
| Французский жим сидя | 22.5 | 9-10-10-8 |
|
||||||
|
| Жим от плеч вверх сидя | 20х2 | 12-12-12-10 |
|
||||||
|
|
||||||
|
# 2025-09-27 (solo-103)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ----------------------------------------- | ----- | ----------- |
|
||||||
|
| Подтягивания | | 10-7-6-5 |
|
||||||
|
| Тяга вертикального блока | 60 | 15-14-13-14 |
|
||||||
|
| Жим гантелей лежа | 22х2 | 12-12-12-11 |
|
||||||
|
| Жим от груди сидя в тренажёре (кирпичики) | 70-55 | 10-15-15-17 |
|
||||||
|
| Пресс на скамье | | 12-12-12 |
|
||||||
|
|
||||||
|
# 2025-09-24 (solo-102)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ------------ | ----------- |
|
||||||
|
| Подъем штанги стоя | 35 | 10-10-10-9 |
|
||||||
|
| Подъем гантелей на предплечье обратным хватом | 17.5х2 | 12-12-12-12 |
|
||||||
|
| Французский жим лежа со штангой | 20-25 | 12-12-12-12 |
|
||||||
|
| Поворот гантели на лямке | 8х2-10x2-8x2 | 12-9-12-12 |
|
||||||
|
| Жим от плеч вверх сидя с гантелями | 22.5х2 | 12-11-10-9 |
|
||||||
|
|
||||||
|
# 2025-09-22 (solo-101)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ---------------------------------------- | ----------- | ----------- |
|
||||||
|
| Подтягивания | | 10-7-6-5 |
|
||||||
|
| Гребная тяга с упором в грудь | 80-80-85 | 12-12-12-12 |
|
||||||
|
| Жим гантелей лежа | 22.5х2-25х2 | 12-12-9-8 |
|
||||||
|
| Жим от груди сидя в тренажёре (блинчики) | 30х2 | 8-9-8-8 |
|
||||||
|
| Махи гантелей стоя | 12.5х2 | 12-12-12-12 |
|
||||||
|
|
||||||
|
# 2025-09-20 (solo-100)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| -------------------------- | ------- | ----------- |
|
||||||
|
| Подьем штанги стоя | 30 | 12-12-12-12 |
|
||||||
|
| Молоты стоя (наискосок) | 15х2 | 12-12-12-12 |
|
||||||
|
| Французский жим с гантелей | 20-22.5 | 12-10-12-10 |
|
||||||
|
| Поворот гантели на лямке | 8х2 | 12-12-12-12 |
|
||||||
|
| Пресс на скамье | | 15-12-12-12 |
|
||||||
|
|
||||||
|
# 2025-09-18 (solo-99)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ----------------------------------------- | ---- | ----------- |
|
||||||
|
| Подтягивания | | 10-6-6-6 |
|
||||||
|
| Тяга Т-грифа | 40 | 12-12-12-10 |
|
||||||
|
| Жим от груди лежа с гантелями | 25х2 | 10-10-10-10 |
|
||||||
|
| Жим от груди сидя в тренажёре (кирпичики) | 70 | 12-12-12-12 |
|
||||||
|
| Разведение рук пек-дек | 35 | 12-12-10-11 |
|
||||||
|
|
||||||
|
# 2025-09-15 (solo-98)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ------ | ----------- |
|
||||||
|
| Молоты стоя (наискосок) | 15х2 | 12-12-12-12 |
|
||||||
|
| Отжимания на трицепс в кроссовере | 60 | 12-12-11-10 |
|
||||||
|
| Подъем гантелей на предплечье обратным хватом | 15х2 | 12-12-12-12 |
|
||||||
|
| Жим от плеч вверх сидя с гантелями | 22.5х2 | 10-12-8-5 |
|
||||||
|
| Махи гантелей в сторону | 10х2 | 12-12- |
|
||||||
|
|
||||||
|
# 2025-09-13 (solo-97)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ------------------------------------ | ----- | ----------- |
|
||||||
|
| Подтягивания | | 10-7-6-6 |
|
||||||
|
| Тяга вертикального блока (кирпичики) | 80-85 | 12-12-12-12 |
|
||||||
|
| Жим от груди лежа с гантелями | 25х2 | 12-11-8-10 |
|
||||||
|
| Сведение рук пек-дек | 65-60 | 8-10-9-10 |
|
||||||
|
| Подъем ног в висе | | 12-10-10-7 |
|
||||||
|
|
||||||
|
# 2025-09-10 (solo-96)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ------ | ----------- |
|
||||||
|
| Подъем штанги стоя | 30 | 12-12-12-12 |
|
||||||
|
| Молоты стоя | 15х2 | 12-12-12- |
|
||||||
|
| Поворот гантели на лямке | 8х2 | 12-12-12-12 |
|
||||||
|
| Отжимания на трицепс в кроссовере | 60 | 12-11-11-10 |
|
||||||
|
| Жим от плеч вверх сидя в тренажёре (блинчики) | 17.5х2 | 10-10-9-8 |
|
||||||
|
|
||||||
|
# 2025-09-08 (solo-95)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ---------------------------------------- | ---- | ----------- |
|
||||||
|
| Подтягивания | | 10-8-7-7 |
|
||||||
|
| Тяга Т-грифа | 35 | 12-12-12-12 |
|
||||||
|
| Жим гантелей лежа | 25х2 | 12-11-9-9 |
|
||||||
|
| Жим от груди сидя в тренажере (блинчики) | 30х2 | 7-10-8-9 |
|
||||||
|
| Пресс на наклонной скамье | | 15-12-12-12 |
|
||||||
|
|
||||||
|
# 2025-09-06 (solo-94)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| --------------------------------------------- | ---------------- | ----------- |
|
||||||
|
| Молоты стоя (наискосок) | 15х2 | 12-12-12-12 |
|
||||||
|
| Молоты стоя | 12.5х2-15х2 | 12-12-12-12 |
|
||||||
|
| Подъем гантелей на предплечья обратным хватом | 10х2-12.5х2-15х2 | 15-15-12-12 |
|
||||||
|
| Отжимания на трицепс в кроссовере | 60 | 12-12-12-10 |
|
||||||
|
| Жим от плеч вверх сидя с гантелями | 22.5х2 | 9-8-8-8 |
|
||||||
|
|
||||||
|
# 2025-09-04 (solo-93)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| -------------------------- | ----------- | ----------- |
|
||||||
|
| Подтягивания | | 10-8-7-6 |
|
||||||
|
| Тяга горизонтального блока | 60-65-65-60 | 12-12-12-12 |
|
||||||
|
| Сведение рук пек-дек | 60-65 | 12-12-10-8 |
|
||||||
|
| Жим гантелей лежа | 25х2 | 9-9-9-9 |
|
||||||
|
| Пресс на скамье | | 12-13-12-12 |
|
||||||
|
# 2025-09-01 (solo-92)
|
||||||
|
|
||||||
|
| Упражнение | Вес | Подходы |
|
||||||
|
| ---------------------------------- | --------------------- | ----------- |
|
||||||
|
| Подъем штанги стоя | 30 | 12-12-12-12 |
|
||||||
|
| Молоты стоя (наискосок) | 15х2-15х2-15х2-12.5х2 | 10-11-10-12 |
|
||||||
|
| Молоты лежа | 12.5х2-15x2 | 12-12-12-12 |
|
||||||
|
| Поворот гантели на лямке | 6х2-6х2-8х2 | 12-12-12-12 |
|
||||||
|
| Жим от плеч вверх сидя с гантелями | 22.5х2 | 12-11-9-8 |
|
||||||
|
|
||||||
# 2025-08-30 (solo-91)
|
# 2025-08-30 (solo-91)
|
||||||
|
|
||||||
| Упражнение | Вес | Подходы |
|
| Упражнение | Вес | Подходы |
|
||||||
|
|
|
||||||
44
dump_trainings.py
Normal file
44
dump_trainings.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import json
|
||||||
|
from typing import List
|
||||||
|
from app.core.parsers.apple import parse_training_data as adp
|
||||||
|
from app.core.parsers.obsidian import parse_training_data as odp
|
||||||
|
from app.core.dto.training import TrainingDTO
|
||||||
|
|
||||||
|
|
||||||
|
def dump_trainings_to_json(trainings: List[TrainingDTO], filename="trainings.json"):
|
||||||
|
"""Dump training data to JSON file using DTO format."""
|
||||||
|
trainings_data = []
|
||||||
|
|
||||||
|
for training in trainings:
|
||||||
|
training_dict = training.model_dump()
|
||||||
|
trainings_data.append(training_dict)
|
||||||
|
|
||||||
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(trainings_data, f, indent=2, ensure_ascii=False, default=str)
|
||||||
|
|
||||||
|
print(f"Trainings dumped to {filename}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Parse Obsidian notes
|
||||||
|
obsidian_trainings = odp()
|
||||||
|
for training in obsidian_trainings:
|
||||||
|
for exercise in training.exercises:
|
||||||
|
print(exercise.name)
|
||||||
|
|
||||||
|
# Parse Apple notes
|
||||||
|
apple_trainings = adp()
|
||||||
|
|
||||||
|
# Combine trainings
|
||||||
|
all_trainings = obsidian_trainings + apple_trainings
|
||||||
|
|
||||||
|
print(f"Obsidian trainings: {len(obsidian_trainings)}")
|
||||||
|
print(f"Apple trainings: {len(apple_trainings)}")
|
||||||
|
print(f"Total trainings: {len(all_trainings)}")
|
||||||
|
|
||||||
|
# Dump to JSON
|
||||||
|
dump_trainings_to_json(all_trainings)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
0
migrations/__init__.py
Normal file
0
migrations/__init__.py
Normal file
76
migrations/runner.py
Normal file
76
migrations/runner.py
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||||
|
from sqlalchemy import text
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationRunner:
|
||||||
|
MIGRATIONS_SCHEMA_NAME: str = "schema_migrations"
|
||||||
|
|
||||||
|
def __init__(self, database_url: str) -> None:
|
||||||
|
self.engine = create_async_engine(database_url)
|
||||||
|
self.migrations_dir = Path("migrations/sql")
|
||||||
|
logging.info(
|
||||||
|
f"Migrator initializer: engine = {self.engine}, migrations_dir = {self.migrations_dir}"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_applied_migrations(self) -> set:
|
||||||
|
"""Get list of applied migrations"""
|
||||||
|
async with self.engine.begin() as conn:
|
||||||
|
# Create migrations list table if not exists
|
||||||
|
await conn.execute(
|
||||||
|
text(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS {self.MIGRATIONS_SCHEMA_NAME} (
|
||||||
|
version VARCHAR(50) PRIMARY KEY,
|
||||||
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Receiving list of applied migrations
|
||||||
|
result = await conn.execute(
|
||||||
|
text(f"SELECT version FROM {self.MIGRATIONS_SCHEMA_NAME}")
|
||||||
|
)
|
||||||
|
result_data = {row[0] for row in result.fetchall()}
|
||||||
|
logging.info(f"Received migrator data: {result_data}")
|
||||||
|
return result_data
|
||||||
|
|
||||||
|
async def run_migrations(self):
|
||||||
|
"""Run all unapplied migrations"""
|
||||||
|
applied = await self.get_applied_migrations()
|
||||||
|
logging.info(f"Applied migrations: {applied}")
|
||||||
|
|
||||||
|
# Getting all sql files from migrations_dir
|
||||||
|
# TODO: (#ToLearn) Read about Path.glob function
|
||||||
|
migration_files = self.migrations_dir.glob('.*sql')
|
||||||
|
migration_files = sorted([file for file in self.migrations_dir.glob("*.sql")])
|
||||||
|
logging.info(f"Migration files: {migration_files}")
|
||||||
|
|
||||||
|
for migration_file in migration_files:
|
||||||
|
# TODO: (#ToLearn) Read about stem property
|
||||||
|
migration_name = migration_file.stem
|
||||||
|
|
||||||
|
if migration_name not in applied:
|
||||||
|
logging.info(f"Applying migration: {migration_name}")
|
||||||
|
await self._apply_migration(migration_file, migration_name)
|
||||||
|
else:
|
||||||
|
logging.info(f"Skipping migration: {migration_name} (already applied)")
|
||||||
|
|
||||||
|
async def _apply_migration(self, migration_file: Path, migration_name: str):
|
||||||
|
"""Apply migrations from migrations/sql folder"""
|
||||||
|
with open(migration_file, "r", encoding="utf-8") as f:
|
||||||
|
sql_content = f.read()
|
||||||
|
|
||||||
|
async with self.engine.begin() as conn:
|
||||||
|
try:
|
||||||
|
statements = [s.strip() for s in sql_content.split(";") if s.strip()]
|
||||||
|
|
||||||
|
for statement in statements:
|
||||||
|
if statement:
|
||||||
|
await conn.execute(text(statement))
|
||||||
|
|
||||||
|
logging.info(f"Migration {migration_name} applied successfully")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error applying migration {migration_name}: {e}")
|
||||||
|
raise
|
||||||
19
migrations/sql/0001_initial.sql
Normal file
19
migrations/sql/0001_initial.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
-- Migration: 0001_initial
|
||||||
|
-- Description: Create initial migration with user for f1tness app
|
||||||
|
|
||||||
|
-- Default user schema
|
||||||
|
-- TODO: (#ToLearn) Read about TIMESTAMP and CURRENT_TIMESTAMP
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(250) UNIQUE NOT NULL,
|
||||||
|
email VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Schema for tracking applied migrations
|
||||||
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||||
|
version VARCHAR(50) PRIMARY KEY,
|
||||||
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('0001_initial');
|
||||||
28
migrations/sql/0002_trainings.sql
Normal file
28
migrations/sql/0002_trainings.sql
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
-- Migration: 0002_trainings
|
||||||
|
-- Description: Basic migration to initialize and create basic tarinings table
|
||||||
|
|
||||||
|
-- Schemas for trainings
|
||||||
|
-- Trainings table
|
||||||
|
CREATE TABLE IF NOT EXISTS trainings (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
date DATE NOT NULL,
|
||||||
|
trainer VARCHAR(100)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Exercies table
|
||||||
|
CREATE TABLE IF NOT EXISTS exercises (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
training_id INTEGER REFERENCES trainings(id) ON DELETE CASCADE,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
splitted_weigh BOOLEAN DEFAULT FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Approaches table
|
||||||
|
CREATE TABLE IF NOT EXISTS approaches (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
approach_id INTEGER REFERENCES approaches(id) ON DELETE CASCADE,
|
||||||
|
weight FLOAT NOT NULL,
|
||||||
|
reps INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('0002_trainings');
|
||||||
37
migrations/sql/0003_fix_trainings_id.sql
Normal file
37
migrations/sql/0003_fix_trainings_id.sql
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
-- Migration: 0003_fix_trainings_id
|
||||||
|
-- Description: Fix trainings table to use proper SQLite autoincrement ID
|
||||||
|
|
||||||
|
-- Drop the existing trainings table (data will be lost)
|
||||||
|
DROP TABLE IF EXISTS trainings;
|
||||||
|
|
||||||
|
-- Recreate with proper SQLite syntax
|
||||||
|
CREATE TABLE trainings (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
date DATE NOT NULL,
|
||||||
|
trainer VARCHAR(100),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Also fix exercises table if it exists
|
||||||
|
DROP TABLE IF EXISTS exercises;
|
||||||
|
CREATE TABLE exercises (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
training_id INTEGER NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
splitted_weight BOOLEAN DEFAULT 0,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (training_id) REFERENCES trainings(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Fix approaches table if it exists
|
||||||
|
DROP TABLE IF EXISTS approaches;
|
||||||
|
CREATE TABLE approaches (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
exercise_id INTEGER NOT NULL,
|
||||||
|
weight REAL,
|
||||||
|
reps INTEGER,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (exercise_id) REFERENCES exercises(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('0003_fix_trainings_id');
|
||||||
|
|
@ -13,6 +13,9 @@ dependencies = [
|
||||||
"python-dotenv>=1.0.1",
|
"python-dotenv>=1.0.1",
|
||||||
"jinja2>=3.1.0",
|
"jinja2>=3.1.0",
|
||||||
"python-multipart>=0.0.6",
|
"python-multipart>=0.0.6",
|
||||||
|
"sqlalchemy>=2.0.43",
|
||||||
|
"asyncpg>=0.30.0",
|
||||||
|
"aiosqlite>=0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
@ -21,3 +24,7 @@ dev = [
|
||||||
"types-grpcio>=1.0.0.20250703",
|
"types-grpcio>=1.0.0.20250703",
|
||||||
"types-protobuf>=6.30.2.20250822",
|
"types-protobuf>=6.30.2.20250822",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tools.pyright]
|
||||||
|
venvPath = "."
|
||||||
|
venv = ".venv"
|
||||||
|
|
|
||||||
79
uv.lock
79
uv.lock
|
|
@ -2,6 +2,18 @@ version = 1
|
||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiosqlite"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/13/7d/8bca2bf9a247c2c5dfeec1d7a5f40db6518f88d314b8bca9da29670d2671/aiosqlite-0.21.0.tar.gz", hash = "sha256:131bb8056daa3bc875608c631c678cda73922a2d4ba8aec373b19f18c17e7aa3", size = 13454, upload-time = "2025-02-03T07:30:16.235Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/10/6c25ed6de94c49f88a91fa5018cb4c0f3625f31d5be9f771ebe5cc7cd506/aiosqlite-0.21.0-py3-none-any.whl", hash = "sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0", size = 15792, upload-time = "2025-02-03T07:30:13.6Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
|
@ -24,6 +36,22 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" },
|
{ url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asyncpg"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2f/4c/7c991e080e106d854809030d8584e15b2e996e26f16aee6d757e387bc17d/asyncpg-0.30.0.tar.gz", hash = "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851", size = 957746, upload-time = "2024-10-20T00:30:41.127Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/22/e20602e1218dc07692acf70d5b902be820168d6282e69ef0d3cb920dc36f/asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70", size = 670373, upload-time = "2024-10-20T00:29:55.165Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/b3/0cf269a9d647852a95c06eb00b815d0b95a4eb4b55aa2d6ba680971733b9/asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3", size = 634745, upload-time = "2024-10-20T00:29:57.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/6d/a4f31bf358ce8491d2a31bfe0d7bcf25269e80481e49de4d8616c4295a34/asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33", size = 3512103, upload-time = "2024-10-20T00:29:58.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/19/139227a6e67f407b9c386cb594d9628c6c78c9024f26df87c912fabd4368/asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4", size = 3592471, upload-time = "2024-10-20T00:30:00.354Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/e4/ab3ca38f628f53f0fd28d3ff20edff1c975dd1cb22482e0061916b4b9a74/asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4", size = 3496253, upload-time = "2024-10-20T00:30:02.794Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/5f/0bf65511d4eeac3a1f41c54034a492515a707c6edbc642174ae79034d3ba/asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba", size = 3662720, upload-time = "2024-10-20T00:30:04.501Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/31/1513d5a6412b98052c3ed9158d783b1e09d0910f51fbe0e05f56cc370bc4/asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590", size = 560404, upload-time = "2024-10-20T00:30:06.537Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/a4/cec76b3389c4c5ff66301cd100fe88c318563ec8a520e0b2e792b5b84972/asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e", size = 621623, upload-time = "2024-10-20T00:30:09.024Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.2.1"
|
version = "8.2.1"
|
||||||
|
|
@ -50,6 +78,8 @@ name = "f1tness-parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "aiosqlite" },
|
||||||
|
{ name = "asyncpg" },
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
|
|
@ -57,6 +87,7 @@ dependencies = [
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
{ name = "python-multipart" },
|
{ name = "python-multipart" },
|
||||||
|
{ name = "sqlalchemy" },
|
||||||
{ name = "uvicorn", extra = ["standard"] },
|
{ name = "uvicorn", extra = ["standard"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -69,6 +100,8 @@ dev = [
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "aiosqlite", specifier = ">=0.21.0" },
|
||||||
|
{ name = "asyncpg", specifier = ">=0.30.0" },
|
||||||
{ name = "fastapi", specifier = ">=0.115.0" },
|
{ name = "fastapi", specifier = ">=0.115.0" },
|
||||||
{ name = "jinja2", specifier = ">=3.1.0" },
|
{ name = "jinja2", specifier = ">=3.1.0" },
|
||||||
{ name = "pydantic", specifier = ">=2.11.7" },
|
{ name = "pydantic", specifier = ">=2.11.7" },
|
||||||
|
|
@ -76,6 +109,7 @@ requires-dist = [
|
||||||
{ name = "pytest", specifier = ">=8.3.4" },
|
{ name = "pytest", specifier = ">=8.3.4" },
|
||||||
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
||||||
{ name = "python-multipart", specifier = ">=0.0.6" },
|
{ name = "python-multipart", specifier = ">=0.0.6" },
|
||||||
|
{ name = "sqlalchemy", specifier = ">=2.0.43" },
|
||||||
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" },
|
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -100,6 +134,30 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" },
|
{ url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "greenlet"
|
||||||
|
version = "3.2.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h11"
|
name = "h11"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
|
@ -370,6 +428,27 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlalchemy"
|
||||||
|
version = "2.0.43"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/bc/d59b5d97d27229b0e009bd9098cd81af71c2fa5549c580a0a67b9bed0496/sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417", size = 9762949, upload-time = "2025-08-11T14:24:58.438Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/1c/a7260bd47a6fae7e03768bf66451437b36451143f36b285522b865987ced/sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3", size = 2130598, upload-time = "2025-08-11T15:51:15.903Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/84/8a337454e82388283830b3586ad7847aa9c76fdd4f1df09cdd1f94591873/sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa", size = 2118415, upload-time = "2025-08-11T15:51:17.256Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/ff/22ab2328148492c4d71899d62a0e65370ea66c877aea017a244a35733685/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9", size = 3248707, upload-time = "2025-08-11T15:52:38.444Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/29/11ae2c2b981de60187f7cbc84277d9d21f101093d1b2e945c63774477aba/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f", size = 3253602, upload-time = "2025-08-11T15:56:37.348Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/61/987b6c23b12c56d2be451bc70900f67dd7d989d52b1ee64f239cf19aec69/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738", size = 3183248, upload-time = "2025-08-11T15:52:39.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/85/29d216002d4593c2ce1c0ec2cec46dda77bfbcd221e24caa6e85eff53d89/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164", size = 3219363, upload-time = "2025-08-11T15:56:39.11Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/e4/bd78b01919c524f190b4905d47e7630bf4130b9f48fd971ae1c6225b6f6a/sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d", size = 2096718, upload-time = "2025-08-11T15:55:05.349Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/a5/ca2f07a2a201f9497de1928f787926613db6307992fe5cda97624eb07c2f/sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197", size = 2123200, upload-time = "2025-08-11T15:55:07.932Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/d9/13bdde6521f322861fab67473cec4b1cc8999f3871953531cf61945fad92/sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc", size = 1924759, upload-time = "2025-08-11T15:39:53.024Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "starlette"
|
name = "starlette"
|
||||||
version = "0.47.3"
|
version = "0.47.3"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue