diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 478156e..800d6d3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,6 +40,14 @@ jobs: context: ./backend push: true tags: jahleelt/commutesmart-backend:latest + + - name: Build and push ml-service image + if: false # Change to true or conditionally enable later + uses: docker/build-push-action@v4 + with: + context: ./ml + push: true + tags: jahleelt/commutesmart-ml:latest - name: Final success message if: always() diff --git a/.github/workflows/ml.yml b/.github/workflows/ml.yml new file mode 100644 index 0000000..7e89116 --- /dev/null +++ b/.github/workflows/ml.yml @@ -0,0 +1,37 @@ +name: ML Service CI + +on: + push: + paths: + - 'ml/**' + - '.github/workflows/ml.yml' + pull_request: + paths: + - 'ml/**' + +jobs: + build-ml: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + working-directory: ml + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run basic test (placeholder) + working-directory: ml + run: | + echo "Running placeholder ML tests..." + python main.py & # if main.py is FastAPI, this just checks it runs + sleep 2 + curl -f http://localhost:8002/ || echo "Did not respond" # Optional check diff --git a/docker-compose.yml b/docker-compose.yml index 2b0f3bf..d6e35bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,4 +12,16 @@ services: backend: build: ./backend ports: - - "8080:8080" \ No newline at end of file + - "8080:8080" + depends_on: + - ml-service + + ml-service: + build: + context: ./ml + ports: + - "8002:8002" + environment: + - PYTHONPATH=/app + volumes: + - ./ml:/app \ No newline at end of file diff --git a/ml/.gitignore b/ml/.gitignore new file mode 100644 index 0000000..f8cdfc4 --- /dev/null +++ b/ml/.gitignore @@ -0,0 +1,110 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual Environment +venv/ +env/ +ENV/ +.venv/ +.env/ + +# Environment variables +.env +.env.local +.env.development +.env.test +.env.production + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Jupyter Notebooks +.ipynb_checkpoints +*.ipynb + +# ML/Data Science specific +# Trained models +*.pkl +*.joblib +*.h5 +*.pb +*.onnx +*.tflite +models/saved/ +checkpoints/ +weights/ + +# Data files +*.csv +*.json +*.parquet +*.feather +data/ +datasets/ +raw_data/ +processed_data/ + +# Logs +*.log +logs/ +mlruns/ +runs/ + +# Cache +.cache/ +.pytest_cache/ +.coverage +htmlcov/ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Temporary files +*.tmp +*.temp +temp/ +tmp/ + +# MLflow +mlruns/ +mlartifacts/ + +# Weights & Biases +wandb/ + +# TensorBoard +tensorboard_logs/ + +# Docker +.dockerignore \ No newline at end of file diff --git a/ml/Dockerfile b/ml/Dockerfile new file mode 100644 index 0000000..557d240 --- /dev/null +++ b/ml/Dockerfile @@ -0,0 +1,13 @@ +# TODO ml/Dockerfile (this is a production ready placeholder) + +FROM python:3.11-slim + +WORKDIR /app + +# Avoid caching issues +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002"] diff --git a/ml/__init__.py b/ml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ml/main.py b/ml/main.py new file mode 100644 index 0000000..b3e99f3 --- /dev/null +++ b/ml/main.py @@ -0,0 +1,25 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +import uvicorn + +app = FastAPI(title="CommuteSmartAI ML Service") + +# CORS middleware for frontend communication +app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:3000"], # Your frontend URL + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +@app.get("/") +async def root(): + return {"message": "CommuteSmartAI ML Service is running"} + +@app.get("/health") +async def health_check(): + return {"status": "healthy"} + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8002) \ No newline at end of file diff --git a/ml/requirements.txt b/ml/requirements.txt new file mode 100644 index 0000000..eea56cd --- /dev/null +++ b/ml/requirements.txt @@ -0,0 +1,8 @@ +fastapi==0.104.1 +uvicorn==0.24.0 +pydantic==2.5.0 +numpy==1.24.3 +pandas==2.0.3 +scikit-learn==1.3.0 +requests==2.31.0 +python-dotenv==1.0.0 \ No newline at end of file