mirror of
https://github.com/escalante29/healthy-fit.git
synced 2026-03-21 13:48:46 +01:00
Initial project scaffolding for health tracker app
Set up backend and frontend structure for a health and fitness tracker using Python (FastAPI, SQLModel, DSPy) and React. Includes Docker and Compose configs, authentication, nutrition AI module, health/nutrition/user endpoints, database models, and basic frontend with routing and context. Enables tracking nutrition, health metrics, and user management, with architecture ready for future mobile and cloud deployment.
This commit is contained in:
0
backend/app/api/v1/__init__.py
Normal file
0
backend/app/api/v1/__init__.py
Normal file
8
backend/app/api/v1/api.py
Normal file
8
backend/app/api/v1/api.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from fastapi import APIRouter
|
||||
from app.api.v1.endpoints import users, login, nutrition, health
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(login.router, tags=["login"])
|
||||
api_router.include_router(users.router, prefix="/users", tags=["users"])
|
||||
api_router.include_router(nutrition.router, prefix="/nutrition", tags=["nutrition"])
|
||||
api_router.include_router(health.router, prefix="/health", tags=["health"])
|
||||
0
backend/app/api/v1/endpoints/__init__.py
Normal file
0
backend/app/api/v1/endpoints/__init__.py
Normal file
35
backend/app/api/v1/endpoints/health.py
Normal file
35
backend/app/api/v1/endpoints/health.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from typing import Any, List
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlmodel import Session, select
|
||||
from app.api import deps
|
||||
from app.models.health import HealthMetric
|
||||
from pydantic import BaseModel
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class HealthMetricCreate(BaseModel):
|
||||
metric_type: str
|
||||
value: float
|
||||
unit: str
|
||||
user_id: int # TODO: remove when auth is fully integrated
|
||||
|
||||
@router.post("/", response_model=HealthMetric)
|
||||
def create_metric(
|
||||
*,
|
||||
session: Session = Depends(deps.get_session),
|
||||
metric_in: HealthMetricCreate,
|
||||
) -> Any:
|
||||
metric = HealthMetric(metric_type=metric_in.metric_type, value=metric_in.value, unit=metric_in.unit, user_id=metric_in.user_id)
|
||||
session.add(metric)
|
||||
session.commit()
|
||||
session.refresh(metric)
|
||||
return metric
|
||||
|
||||
@router.get("/{user_id}", response_model=List[HealthMetric])
|
||||
def read_metrics(
|
||||
user_id: int,
|
||||
session: Session = Depends(deps.get_session),
|
||||
) -> Any:
|
||||
statement = select(HealthMetric).where(HealthMetric.user_id == user_id)
|
||||
metrics = session.exec(statement).all()
|
||||
return metrics
|
||||
35
backend/app/api/v1/endpoints/login.py
Normal file
35
backend/app/api/v1/endpoints/login.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.api import deps
|
||||
from app.core import security
|
||||
from app.config import settings
|
||||
from app.models.user import User
|
||||
from app.schemas.token import Token
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/login/access-token", response_model=Token)
|
||||
def login_access_token(
|
||||
session: Session = Depends(deps.get_session),
|
||||
form_data: OAuth2PasswordRequestForm = Depends()
|
||||
) -> Any:
|
||||
"""
|
||||
OAuth2 compatible token login, get an access token for future requests
|
||||
"""
|
||||
statement = select(User).where(User.email == form_data.username)
|
||||
user = session.exec(statement).first()
|
||||
|
||||
if not user or not security.verify_password(form_data.password, user.password_hash):
|
||||
raise HTTPException(status_code=400, detail="Incorrect email or password")
|
||||
|
||||
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
return {
|
||||
"access_token": security.create_access_token(
|
||||
user.id, expires_delta=access_token_expires
|
||||
),
|
||||
"token_type": "bearer",
|
||||
}
|
||||
54
backend/app/api/v1/endpoints/nutrition.py
Normal file
54
backend/app/api/v1/endpoints/nutrition.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from typing import Any
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlmodel import Session
|
||||
from app.api import deps
|
||||
from app.ai.nutrition import nutrition_module, NutritionalInfo
|
||||
from app.core.security import create_access_token # Just ensuring we have auth imports if needed later
|
||||
from app.models.user import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class AnalyzeRequest(BaseModel):
|
||||
description: str
|
||||
|
||||
from app.models.food import FoodLog, FoodItem
|
||||
from app.api.deps import get_session
|
||||
from app.core.security import get_password_hash # Not needed
|
||||
from app.config import settings
|
||||
|
||||
@router.post("/analyze", response_model=NutritionalInfo)
|
||||
def analyze_food(
|
||||
request: AnalyzeRequest,
|
||||
) -> Any:
|
||||
"""
|
||||
Analyze food description and return nutritional info using DSPy.
|
||||
"""
|
||||
try:
|
||||
result = nutrition_module(description=request.description)
|
||||
return result.nutritional_info
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.post("/log", response_model=FoodLog)
|
||||
def log_food(
|
||||
*,
|
||||
session: Session = Depends(deps.get_session),
|
||||
nutrition_info: NutritionalInfo,
|
||||
current_user: deps.CurrentUser,
|
||||
) -> Any:
|
||||
"""
|
||||
Save food log to database.
|
||||
"""
|
||||
food_log = FoodLog(
|
||||
user_id=current_user.id,
|
||||
name=nutrition_info.name,
|
||||
calories=nutrition_info.calories,
|
||||
protein=nutrition_info.protein,
|
||||
carbs=nutrition_info.carbs,
|
||||
fats=nutrition_info.fats,
|
||||
)
|
||||
session.add(food_log)
|
||||
session.commit()
|
||||
session.refresh(food_log)
|
||||
return food_log
|
||||
36
backend/app/api/v1/endpoints/users.py
Normal file
36
backend/app/api/v1/endpoints/users.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from typing import Any
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.api import deps
|
||||
from app.core import security
|
||||
from app.models.user import User
|
||||
from app.schemas.user import UserCreate, UserRead
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/", response_model=UserRead)
|
||||
def create_user(
|
||||
*,
|
||||
session: Session = Depends(deps.get_session),
|
||||
user_in: UserCreate,
|
||||
) -> Any:
|
||||
"""
|
||||
Create new user.
|
||||
"""
|
||||
user = session.exec(select(User).where(User.email == user_in.email)).first()
|
||||
if user:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="The user with this email already exists in the system",
|
||||
)
|
||||
|
||||
user = User(
|
||||
email=user_in.email,
|
||||
username=user_in.username,
|
||||
password_hash=security.get_password_hash(user_in.password),
|
||||
)
|
||||
session.add(user)
|
||||
session.commit()
|
||||
session.refresh(user)
|
||||
return user
|
||||
Reference in New Issue
Block a user