Jordandevlog's picture
Duplicate from Jordandevlog/ai-dev-template
4aec5bd
Raw
History Blame Contribute Delete
9.06 kB
#!/usr/bin/env bash
set -euo pipefail
echo "🚀 AI-Assisted Development Environment Setup"
echo "=============================================="
# Detect OS
OS="unknown"
case "$(uname -s)" in
Linux*) OS="linux";;
Darwin*) OS="macos";;
CYGWIN*|MINGW*|MSYS*) OS="windows";;
esac
echo "Detected OS: $OS"
# --- 1. Check Python ---
echo ""
echo "📦 Checking Python..."
if ! command -v python3 &> /dev/null; then
echo "❌ Python 3 not found. Please install Python 3.11+."
exit 1
fi
PYTHON_VERSION=$(python3 --version | grep -oE '[0-9]+\.[0-9]+')
echo "✓ Python $PYTHON_VERSION found"
# --- 2. Create virtual environment ---
echo ""
echo "🌿 Setting up virtual environment..."
if [ ! -d ".venv" ]; then
python3 -m venv .venv
echo "✓ Created .venv/"
else
echo "✓ .venv/ already exists"
fi
source .venv/bin/activate
# --- 3. Install Python dependencies ---
echo ""
echo "📥 Installing Python dependencies..."
pip install --upgrade pip
# Core
pip install fastapi uvicorn pydantic pydantic-settings sqlalchemy pytest pytest-asyncio \
pytest-mock pytest-cov black ruff mypy httpx factory-boy
# AI Agent libraries (optional but recommended)
pip install smolagents openai
echo "✓ Core dependencies installed"
# --- 4. Check Ollama ---
echo ""
echo "🦙 Checking Ollama..."
if command -v ollama &> /dev/null; then
echo "✓ Ollama found"
# Check if gemma4:4b is available
if ollama list | grep -q "gemma4"; then
echo "✓ Gemma 4 model available"
else
echo "⚠ Gemma 4 not found. Pull it with: ollama pull gemma4:4b"
echo " (Optional: ollama pull gemma4:9b for stronger reasoning)"
fi
else
echo "⚠ Ollama not found. Install from https://ollama.com"
echo " After install, run: ollama pull gemma4:4b"
fi
# --- 5. Check Node.js (for MCP servers) ---
echo ""
echo "⬢ Checking Node.js..."
if command -v node &> /dev/null; then
NODE_VERSION=$(node --version)
echo "✓ Node.js $NODE_VERSION found"
else
echo "⚠ Node.js not found. Install for MCP server support."
fi
# --- 6. Check Git ---
echo ""
echo "🔀 Checking Git..."
if [ -d ".git" ]; then
echo "✓ Git repository initialized"
else
git init
echo "✓ Initialized git repository"
fi
# --- 7. Install pre-commit hooks ---
echo ""
echo "🪝 Setting up pre-commit..."
pip install pre-commit
pre-commit install || true
# --- 8. Create .env file ---
echo ""
echo "🔐 Creating .env template..."
if [ ! -f ".env" ]; then
cat > .env << 'EOF'
# Environment Configuration
# Copy this to .env and fill in real values
APP_NAME="MyApp"
DEBUG=true
DATABASE_URL="sqlite:///./app.db"
SECRET_KEY="change-me-in-production"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Hugging Face (optional, for HF model fallback)
HF_TOKEN=""
# Ollama (local)
OLLAMA_BASE_URL="http://localhost:11434"
OLLAMA_MODEL="gemma4:4b"
EOF
echo "✓ Created .env (edit with your values)"
else
echo "✓ .env already exists"
fi
# --- 9. Initialize project structure ---
echo ""
echo "📁 Initializing project structure..."
touch src/__init__.py
touch src/core/__init__.py
touch src/api/__init__.py
touch src/services/__init__.py
touch src/utils/__init__.py
touch tests/__init__.py
touch tests/unit/__init__.py
touch tests/integration/__init__.py
echo "✓ Structure initialized"
# --- 10. Create initial files ---
echo ""
echo "📝 Creating starter files..."
# core/config.py
cat > src/core/config.py << 'EOF'
"""Application configuration using pydantic-settings."""
from functools import lru_cache
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
app_name: str = "MyApp"
debug: bool = False
database_url: str = "sqlite:///./app.db"
secret_key: str = "change-me"
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
@lru_cache
def get_settings() -> Settings:
"""Return cached Settings instance."""
return Settings()
EOF
# core/models.py
cat > src/core/models.py << 'EOF'
"""SQLAlchemy ORM models."""
from sqlalchemy import Column, Integer, String, DateTime, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import func
Base = declarative_base()
class BaseModel:
"""Base model with timestamps."""
id = Column(Integer, primary_key=True, index=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
EOF
# core/database.py
cat > src/core/database.py << 'EOF'
"""Database connection and session management."""
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from .config import get_settings
settings = get_settings()
engine = create_engine(
settings.database_url,
connect_args={"check_same_thread": False} if "sqlite" in settings.database_url else {},
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db() -> Session:
"""Yield a database session. Use as FastAPI dependency."""
db = SessionLocal()
try:
yield db
finally:
db.close()
EOF
# utils/exceptions.py
cat > src/utils/exceptions.py << 'EOF'
"""Custom application exceptions."""
class AppException(Exception):
"""Base application exception."""
def __init__(self, message: str, status_code: int = 500) -> None:
self.message = message
self.status_code = status_code
super().__init__(message)
class ValidationError(AppException):
"""Input validation failed."""
def __init__(self, message: str) -> None:
super().__init__(message, status_code=400)
class NotFoundError(AppException):
"""Resource not found."""
def __init__(self, message: str) -> None:
super().__init__(message, status_code=404)
class AuthenticationError(AppException):
"""Authentication failed."""
def __init__(self, message: str = "Authentication failed") -> None:
super().__init__(message, status_code=401)
EOF
# utils/logger.py
cat > src/utils/logger.py << 'EOF'
"""Structured logging configuration."""
import logging
import sys
from typing import Any
def get_logger(name: str) -> logging.Logger:
"""Return a configured logger."""
logger = logging.getLogger(name)
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter(
"%(asctime)s | %(name)s | %(levelname)s | %(message)s"
)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
EOF
# main.py
cat > src/main.py << 'EOF'
"""FastAPI application entry point."""
from fastapi import FastAPI
from contextlib import asynccontextmanager
from .core.config import get_settings
from .utils.logger import get_logger
logger = get_logger(__name__)
settings = get_settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan events."""
logger.info(f"Starting {settings.app_name}")
yield
logger.info(f"Shutting down {settings.app_name}")
app = FastAPI(
title=settings.app_name,
debug=settings.debug,
lifespan=lifespan,
)
@app.get("/health")
async def health_check() -> dict[str, str]:
"""Health check endpoint."""
return {"status": "ok", "app": settings.app_name}
EOF
# tests/conftest.py
cat > tests/conftest.py << 'EOF'
"""pytest fixtures shared across all tests."""
import pytest
from fastapi.testclient import TestClient
from src.main import app
@pytest.fixture
def client() -> TestClient:
"""Return a FastAPI test client."""
return TestClient(app)
@pytest.fixture
def sample_user() -> dict:
"""Return sample user data."""
return {
"email": "test@example.com",
"password": "securepassword123",
}
EOF
# tests/unit/test_main.py
cat > tests/unit/test_main.py << 'EOF'
"""Tests for main application."""
from fastapi.testclient import TestClient
from src.main import app
class TestHealthCheck:
"""Test health check endpoint."""
def test_health_returns_ok(self, client: TestClient) -> None:
"""Health endpoint should return status ok."""
response = client.get("/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
EOF
echo "✓ Starter files created"
# --- 11. Final instructions ---
echo ""
echo "✅ Setup complete!"
echo ""
echo "Next steps:"
echo " 1. Edit .env with your configuration"
echo " 2. Edit docs/PRD.md with your project requirements"
echo " 3. Start Ollama: ./scripts/start-ollama.sh"
echo " 4. Activate venv: source .venv/bin/activate"
echo " 5. Start coding with AI assistance!"
echo ""
echo "Agent commands:"
echo " python agents/smolagent_runner.py 'your task here'"
echo " python agents/multiagent_workflow.py 'your project here'"