mirror of
https://github.com/sstent/aicyclingcoach-go.git
synced 2026-04-03 19:43:23 +00:00
sync
This commit is contained in:
11
backend/app/models/__init__.py
Normal file
11
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from .base import BaseModel
|
||||
from .route import Route
|
||||
from .section import Section
|
||||
from .rule import Rule
|
||||
from .plan import Plan
|
||||
from .plan_rule import PlanRule
|
||||
from .user import User
|
||||
from .workout import Workout
|
||||
from .analysis import Analysis
|
||||
from .prompt import Prompt
|
||||
from .garmin_sync_log import GarminSyncLog
|
||||
17
backend/app/models/analysis.py
Normal file
17
backend/app/models/analysis.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, JSON, Boolean, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class Analysis(BaseModel):
|
||||
"""Analysis model for AI-generated workout feedback."""
|
||||
__tablename__ = "analyses"
|
||||
|
||||
workout_id = Column(Integer, ForeignKey("workouts.id"), nullable=False)
|
||||
analysis_type = Column(String(50), default='workout_review')
|
||||
jsonb_feedback = Column(JSON) # AI-generated feedback
|
||||
suggestions = Column(JSON) # AI-generated suggestions
|
||||
approved = Column(Boolean, default=False)
|
||||
|
||||
# Relationships
|
||||
workout = relationship("Workout", back_populates="analyses")
|
||||
17
backend/app/models/base.py
Normal file
17
backend/app/models/base.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from datetime import datetime
|
||||
from uuid import UUID, uuid4
|
||||
from sqlalchemy import Column, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class BaseModel(Base):
|
||||
__abstract__ = True
|
||||
|
||||
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid4)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {self.id}>"
|
||||
12
backend/app/models/garmin_sync_log.py
Normal file
12
backend/app/models/garmin_sync_log.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from sqlalchemy import Column, Integer, DateTime, String, Text
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class GarminSyncLog(BaseModel):
|
||||
"""Log model for tracking Garmin sync operations."""
|
||||
__tablename__ = "garmin_sync_log"
|
||||
|
||||
last_sync_time = Column(DateTime)
|
||||
activities_synced = Column(Integer, default=0)
|
||||
status = Column(String(20)) # success, error, in_progress
|
||||
error_message = Column(Text)
|
||||
14
backend/app/models/plan.py
Normal file
14
backend/app/models/plan.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from sqlalchemy import Column, Integer, ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from .base import BaseModel
|
||||
|
||||
class Plan(BaseModel):
|
||||
__tablename__ = "plans"
|
||||
|
||||
jsonb_plan = Column(JSONB, nullable=False)
|
||||
version = Column(Integer, nullable=False)
|
||||
parent_plan_id = Column(Integer, ForeignKey('plans.id'), nullable=True)
|
||||
|
||||
parent_plan = relationship("Plan", remote_side="Plan.id", backref="child_plans")
|
||||
workouts = relationship("Workout", back_populates="plan", cascade="all, delete-orphan")
|
||||
13
backend/app/models/prompt.py
Normal file
13
backend/app/models/prompt.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class Prompt(BaseModel):
|
||||
"""Prompt model for AI prompt versioning and management."""
|
||||
__tablename__ = "prompts"
|
||||
|
||||
action_type = Column(String(50), nullable=False) # plan_generation, workout_analysis, rule_parsing, suggestions
|
||||
model = Column(String(100)) # AI model identifier
|
||||
prompt_text = Column(Text, nullable=False)
|
||||
version = Column(Integer, default=1)
|
||||
active = Column(Boolean, default=True)
|
||||
14
backend/app/models/route.py
Normal file
14
backend/app/models/route.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from sqlalchemy import Column, String, Float, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from .base import BaseModel
|
||||
|
||||
class Route(BaseModel):
|
||||
__tablename__ = "routes"
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(String(500))
|
||||
total_distance = Column(Float, nullable=False)
|
||||
elevation_gain = Column(Float, nullable=False)
|
||||
gpx_file_path = Column(String(255), nullable=False)
|
||||
|
||||
sections = relationship("Section", back_populates="route", cascade="all, delete-orphan")
|
||||
14
backend/app/models/rule.py
Normal file
14
backend/app/models/rule.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from sqlalchemy import Column, Integer, ForeignKey, Boolean
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from .base import BaseModel
|
||||
|
||||
class Rule(BaseModel):
|
||||
__tablename__ = "rules"
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
user_defined = Column(Boolean, default=True)
|
||||
jsonb_rules = Column(JSONB, nullable=False)
|
||||
version = Column(Integer, default=1)
|
||||
parent_rule_id = Column(Integer, ForeignKey('rules.id'), nullable=True)
|
||||
|
||||
parent_rule = relationship("Rule", remote_side="Rule.id")
|
||||
15
backend/app/models/section.py
Normal file
15
backend/app/models/section.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from sqlalchemy import Column, String, Float, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from .base import BaseModel
|
||||
|
||||
class Section(BaseModel):
|
||||
__tablename__ = "sections"
|
||||
|
||||
route_id = Column(ForeignKey("routes.id"), nullable=False)
|
||||
gpx_file_path = Column(String(255), nullable=False)
|
||||
distance_m = Column(Float, nullable=False)
|
||||
grade_avg = Column(Float)
|
||||
min_gear = Column(String(50))
|
||||
est_time_minutes = Column(Float)
|
||||
|
||||
route = relationship("Route", back_populates="sections")
|
||||
7
backend/app/models/user.py
Normal file
7
backend/app/models/user.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .base import BaseModel
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
class User(BaseModel):
|
||||
__tablename__ = "users"
|
||||
|
||||
plans = relationship("Plan", back_populates="user")
|
||||
26
backend/app/models/workout.py
Normal file
26
backend/app/models/workout.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, JSON, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class Workout(BaseModel):
|
||||
"""Workout model for Garmin activity data."""
|
||||
__tablename__ = "workouts"
|
||||
|
||||
plan_id = Column(Integer, ForeignKey("plans.id"), nullable=True)
|
||||
garmin_activity_id = Column(String(255), unique=True, nullable=False)
|
||||
activity_type = Column(String(50))
|
||||
start_time = Column(DateTime, nullable=False)
|
||||
duration_seconds = Column(Integer)
|
||||
distance_m = Column(Float)
|
||||
avg_hr = Column(Integer)
|
||||
max_hr = Column(Integer)
|
||||
avg_power = Column(Float)
|
||||
max_power = Column(Float)
|
||||
avg_cadence = Column(Float)
|
||||
elevation_gain_m = Column(Float)
|
||||
metrics = Column(JSON) # Store full Garmin data as JSONB
|
||||
|
||||
# Relationships
|
||||
plan = relationship("Plan", back_populates="workouts")
|
||||
analyses = relationship("Analysis", back_populates="workout", cascade="all, delete-orphan")
|
||||
Reference in New Issue
Block a user