mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
local setup (#1898)
Signed-off-by: Saurabh Misra <misra.saurabh1@gmail.com> Co-authored-by: saga4 <saga4@codeflashs-MacBook-Air.local> Co-authored-by: Sarthak Agarwal <sarthak.saga@gmail.com> Co-authored-by: Mohamed Ashraf <mohamedashrraf222@gmail.com> Co-authored-by: Aseem Saxena <aseem.bits@gmail.com>
This commit is contained in:
parent
0a49cd32c7
commit
7c1933180a
40 changed files with 2513 additions and 127 deletions
136
.dockerignore
Normal file
136
.dockerignore
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Python virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
django/aiservice/.venv/
|
||||||
|
django/aiservice/venv/
|
||||||
|
django/aiservice/__pycache__/
|
||||||
|
|
||||||
|
# Node.js dependencies
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.next/
|
||||||
|
.nuxt/
|
||||||
|
.vuepress/dist/
|
||||||
|
.serverless/
|
||||||
|
.fusebox/
|
||||||
|
.dynamodb/
|
||||||
|
.tern-port/
|
||||||
|
.vscode-test/
|
||||||
|
|
||||||
|
# Cache directories
|
||||||
|
.cache/
|
||||||
|
.parcel-cache/
|
||||||
|
.eslintcache/
|
||||||
|
.stylelintcache/
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
.tmp/
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
.yarn/cache/
|
||||||
|
.yarn/unplugged/
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# Python cache files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
develop-eggs/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Large directories that shouldn't be in build context
|
||||||
|
experiments/
|
||||||
|
node_modules/
|
||||||
|
js/node_modules/
|
||||||
|
js/cf-api/node_modules/
|
||||||
|
js/cf-webapp/node_modules/
|
||||||
|
js/common/node_modules/
|
||||||
|
django/aiservice/venv/
|
||||||
|
django/aiservice/.venv/
|
||||||
|
|
||||||
|
# Additional large files
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
*.7z
|
||||||
|
*.iso
|
||||||
|
*.dmg
|
||||||
|
|
||||||
|
# Lock files (keep package-lock.json but exclude others)
|
||||||
|
yarn.lock
|
||||||
|
pnpm-lock.yaml
|
||||||
2
.github/workflows/django-unit-tests.yaml
vendored
2
.github/workflows/django-unit-tests.yaml
vendored
|
|
@ -51,6 +51,8 @@ jobs:
|
||||||
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CODEFLASH_AIS_SERVER: local
|
CODEFLASH_AIS_SERVER: local
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||||
|
|
|
||||||
2
.github/workflows/mypy_aiservice.yml
vendored
2
.github/workflows/mypy_aiservice.yml
vendored
|
|
@ -19,6 +19,8 @@ jobs:
|
||||||
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||||
|
OPENAI_API_TYPE: ${{ secrets.OPENAI_API_TYPE }}
|
||||||
|
OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }}
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|
|
||||||
171
deployment/onprem-simple/Dockerfile.unifiedall
Normal file
171
deployment/onprem-simple/Dockerfile.unifiedall
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
# ============================================================================
|
||||||
|
# Codeflash Unified Container - Self-Contained Build
|
||||||
|
# ============================================================================
|
||||||
|
# This Dockerfile builds everything from source without depending on pre-built
|
||||||
|
# images. Use this for client deployments and teammate onboarding.
|
||||||
|
#
|
||||||
|
# Build command:
|
||||||
|
# docker build -f deployment/onprem-simple/Dockerfile.unified-selfcontained \
|
||||||
|
# -t codeflash/unified:latest .
|
||||||
|
#
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Stage 1: Build aiservice
|
||||||
|
# ============================================================================
|
||||||
|
FROM --platform=$BUILDPLATFORM python:3.12-slim AS aiservice-builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install system dependencies for aiservice
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install uv
|
||||||
|
RUN pip install uv
|
||||||
|
|
||||||
|
# Copy aiservice source
|
||||||
|
COPY django/aiservice ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN uv sync
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Stage 2: Build cf-api
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:20-alpine AS cfapi-builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy cf-api and common source
|
||||||
|
COPY js/cf-api ./cf-api
|
||||||
|
COPY js/common ./common
|
||||||
|
|
||||||
|
# Build common package first (cf-api depends on it)
|
||||||
|
WORKDIR /build/common
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# Install ALL dependencies for cf-api (matching Dockerfile.cfapi exactly)
|
||||||
|
WORKDIR /build/cf-api
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Replace the common package from registry with local build
|
||||||
|
RUN rm -rf node_modules/@codeflash-ai/common && \
|
||||||
|
cp -r /build/common node_modules/@codeflash-ai/
|
||||||
|
|
||||||
|
# Clean dist folder before build
|
||||||
|
RUN rm -rf dist
|
||||||
|
|
||||||
|
# Build TypeScript (npm run build does: npm install && prisma generate && tsc && copy-assets)
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Stage 3: Build cf-webapp
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:20-alpine AS webapp-builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy cf-webapp and common source
|
||||||
|
COPY js/cf-webapp ./cf-webapp
|
||||||
|
COPY js/common ./common
|
||||||
|
|
||||||
|
# Build common package first (webapp depends on it)
|
||||||
|
WORKDIR /build/common
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# Install ALL dependencies for webapp
|
||||||
|
WORKDIR /build/cf-webapp
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Replace the common package from registry with local build
|
||||||
|
RUN rm -rf node_modules/@codeflash-ai/common && \
|
||||||
|
cp -r /build/common node_modules/@codeflash-ai/
|
||||||
|
|
||||||
|
# Build Next.js application
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Stage 4: Final unified container
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
postgresql15 \
|
||||||
|
postgresql15-client \
|
||||||
|
supervisor \
|
||||||
|
bash \
|
||||||
|
openssl \
|
||||||
|
build-base \
|
||||||
|
libpq-dev \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# Install Python uv
|
||||||
|
RUN pip3 install --break-system-packages uv
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Copy cf-api from builder
|
||||||
|
# ============================================================================
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/dist ./cf-api/dist
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/package.json ./cf-api/package.json
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/package-lock.json ./cf-api/package-lock.json
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/resend ./cf-api/resend
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/github ./cf-api/github
|
||||||
|
COPY --from=cfapi-builder /build/cf-api/node_modules ./cf-api/node_modules
|
||||||
|
COPY --from=cfapi-builder /build/common /common
|
||||||
|
|
||||||
|
# Copy node_modules into dist (Azure deployment structure)
|
||||||
|
RUN cp -rL /app/cf-api/node_modules /app/cf-api/dist/ 2>/dev/null || cp -r /app/cf-api/node_modules /app/cf-api/dist/
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Copy aiservice from builder
|
||||||
|
# ============================================================================
|
||||||
|
COPY --from=aiservice-builder /app ./aiservice
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Copy cf-webapp from builder
|
||||||
|
# ============================================================================
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/.next ./cf-webapp/.next
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/public ./cf-webapp/public
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/package.json ./cf-webapp/package.json
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/package-lock.json ./cf-webapp/package-lock.json
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/next.config.mjs ./cf-webapp/next.config.mjs
|
||||||
|
COPY --from=webapp-builder /build/cf-webapp/node_modules ./cf-webapp/node_modules
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Configure PostgreSQL
|
||||||
|
# ============================================================================
|
||||||
|
RUN mkdir -p /var/lib/postgresql/data /var/run/postgresql && \
|
||||||
|
chown -R postgres:postgres /var/lib/postgresql /var/run/postgresql
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Copy configuration files
|
||||||
|
# ============================================================================
|
||||||
|
COPY deployment/onprem-simple/supervisord.conf /etc/supervisord.conf
|
||||||
|
COPY deployment/onprem-simple/init-db.sh /app/init-db.sh
|
||||||
|
COPY deployment/onprem-simple/startup.sh /app/startup.sh
|
||||||
|
|
||||||
|
RUN chmod +x /app/init-db.sh /app/startup.sh
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Expose ports
|
||||||
|
# ============================================================================
|
||||||
|
EXPOSE 5432 8000 3001 3000
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Environment variables
|
||||||
|
# ============================================================================
|
||||||
|
ENV PGDATA=/var/lib/postgresql/data
|
||||||
|
ENV PATH="/var/lib/postgresql/bin:${PATH}"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Start services
|
||||||
|
# ============================================================================
|
||||||
|
CMD ["/app/startup.sh"]
|
||||||
341
deployment/onprem-simple/README.md
Normal file
341
deployment/onprem-simple/README.md
Normal file
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Codeflash On-Premise Deployment
|
||||||
|
|
||||||
|
A single Docker container that runs all Codeflash services for on-premise deployments.
|
||||||
|
|
||||||
|
## What's Inside
|
||||||
|
|
||||||
|
The unified container includes:
|
||||||
|
- **PostgreSQL 15** - Database server (port 5432)
|
||||||
|
- **aiservice** - Python Django optimization service (port 8000)
|
||||||
|
- **cf-api** - Node.js API server (port 3001)
|
||||||
|
- **cf-webapp** - Next.js web interface (port 3000)
|
||||||
|
- **Supervisord** - Process manager for all services
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Docker installed (version 20.10 or higher)
|
||||||
|
- An AI provider API key (Azure OpenAI, OpenAI, or Anthropic)
|
||||||
|
|
||||||
|
### Step 1: Build the Docker Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/codeflash-ai/codeflash
|
||||||
|
cd codeflash
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build time:** ~5-10 minutes
|
||||||
|
|
||||||
|
### Step 2: Run the Container
|
||||||
|
|
||||||
|
The simplest way to run Codeflash (only 1 required environment variable!):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name codeflash \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-azure-api-key \
|
||||||
|
-p 5432:5432 \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-p 3001:3001 \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
**What happens automatically:**
|
||||||
|
- ✅ DATABASE_URL defaults to built-in PostgreSQL
|
||||||
|
- ✅ SECRET_KEY auto-generated
|
||||||
|
- ✅ URLs default to localhost
|
||||||
|
- ✅ API key auto-generated on first run
|
||||||
|
|
||||||
|
### Step 3: Get Your API Key
|
||||||
|
|
||||||
|
After the container starts (~15 seconds), retrieve your API key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View logs to see the API key
|
||||||
|
docker logs codeflash
|
||||||
|
|
||||||
|
# Or get it from the saved file
|
||||||
|
docker exec codeflash cat /app/API_KEY.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll see output like:
|
||||||
|
```
|
||||||
|
======================================
|
||||||
|
CODEFLASH SETUP COMPLETE!
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Your API Key: cf-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
|
Save this API key! You'll need it to configure the Codeflash CLI.
|
||||||
|
======================================
|
||||||
|
```
|
||||||
|
|
||||||
|
**Save this API key** - you'll need it for the CLI!
|
||||||
|
|
||||||
|
### Step 4: Install the CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install codeflash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Configure the CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CODEFLASH_API_KEY=cf-your-api-key-from-step-3
|
||||||
|
export CODEFLASH_AIS_SERVER=local
|
||||||
|
export CODEFLASH_CFAPI_SERVER=local
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create a `.env` file in your project:
|
||||||
|
```bash
|
||||||
|
CODEFLASH_API_KEY=cf-your-api-key-from-step-3
|
||||||
|
CODEFLASH_AIS_SERVER=local
|
||||||
|
CODEFLASH_CFAPI_SERVER=local
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Optimize Your Code!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd your-python-project
|
||||||
|
codeflash --file path/to/file.py --function function_name --no-pr
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### Minimal Configuration (Recommended)
|
||||||
|
|
||||||
|
Only provide your AI provider key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name codeflash \
|
||||||
|
-e OPENAI_API_TYPE=azure \
|
||||||
|
-e OPENAI_API_BASE=your-azure-openai-base-url \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Configuration (Optional)
|
||||||
|
|
||||||
|
You can customize all settings if needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name codeflash \
|
||||||
|
-e OPENAI_API_TYPE=azure \
|
||||||
|
-e OPENAI_API_BASE=your-azure-openai-base-url \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-azure-key \
|
||||||
|
-e ANTHROPIC_API_KEY=your-anthropic-key \
|
||||||
|
-e SECRET_KEY=your-custom-secret \
|
||||||
|
-e DATABASE_URL=postgresql://user:pass@host:5432/db \
|
||||||
|
-e NEXT_PUBLIC_APP_URL=http://your-domain:3000 \
|
||||||
|
-e WEBAPP_URL=http://your-domain:3000 \
|
||||||
|
-e CODEFLASH_CFAPI_URL=http://your-domain:3001 \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
See `.env.onprem.minimal` for all available options.
|
||||||
|
|
||||||
|
## Container Management
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if container is running
|
||||||
|
docker ps | grep codeflash
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker logs codeflash
|
||||||
|
|
||||||
|
# Follow logs in real-time
|
||||||
|
docker logs -f codeflash
|
||||||
|
|
||||||
|
# Check service status inside container
|
||||||
|
docker exec codeflash supervisorctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
postgres RUNNING pid 40, uptime 0:10:23
|
||||||
|
aiservice RUNNING pid 41, uptime 0:10:23
|
||||||
|
cf-api RUNNING pid 42, uptime 0:10:23
|
||||||
|
cf-webapp RUNNING pid 43, uptime 0:10:23
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stop/Start/Restart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop container (data persists in volume)
|
||||||
|
docker stop codeflash
|
||||||
|
|
||||||
|
# Start container
|
||||||
|
docker start codeflash
|
||||||
|
|
||||||
|
# Restart container
|
||||||
|
docker restart codeflash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Remove Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove container (keeps data volume)
|
||||||
|
docker stop codeflash
|
||||||
|
docker rm codeflash
|
||||||
|
|
||||||
|
# Remove container AND data (⚠️ deletes all data!)
|
||||||
|
docker stop codeflash
|
||||||
|
docker rm codeflash
|
||||||
|
docker volume rm codeflash-data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upgrade to New Version
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Pull or build new image
|
||||||
|
docker pull codeflash/unified:latest
|
||||||
|
# OR
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:latest .
|
||||||
|
|
||||||
|
# Stop and remove old container
|
||||||
|
docker stop codeflash
|
||||||
|
docker rm codeflash
|
||||||
|
|
||||||
|
# Start new container (data persists in volume)
|
||||||
|
docker run -d --name codeflash \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Accessing Services
|
||||||
|
|
||||||
|
Once running, you can access:
|
||||||
|
|
||||||
|
- **cf-api**: http://localhost:3001
|
||||||
|
- **aiservice**: http://localhost:8000
|
||||||
|
- **cf-webapp**: http://localhost:3000
|
||||||
|
- **PostgreSQL**: localhost:5432 (username: `codeflash`, password: `codeflash`, database: `codeflash`)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container won't start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check logs for errors
|
||||||
|
docker logs codeflash
|
||||||
|
|
||||||
|
# Verify ports are available
|
||||||
|
lsof -i :5432
|
||||||
|
lsof -i :8000
|
||||||
|
lsof -i :3001
|
||||||
|
lsof -i :3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Services not responding
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check service status
|
||||||
|
docker exec codeflash supervisorctl status
|
||||||
|
|
||||||
|
# Restart a specific service
|
||||||
|
docker exec codeflash supervisorctl restart cf-api
|
||||||
|
docker exec codeflash supervisorctl restart aiservice
|
||||||
|
docker exec codeflash supervisorctl restart cf-webapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLI can't connect
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test service endpoints
|
||||||
|
curl http://localhost:3001/cfapi/healthcheck
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
|
# Verify environment variables
|
||||||
|
echo $CODEFLASH_API_KEY
|
||||||
|
echo $CODEFLASH_AIS_SERVER
|
||||||
|
echo $CODEFLASH_CFAPI_SERVER
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if PostgreSQL is ready
|
||||||
|
docker exec codeflash pg_isready -h localhost -p 5432 -U codeflash
|
||||||
|
|
||||||
|
# Access database
|
||||||
|
docker exec -it codeflash psql postgresql://codeflash:codeflash@localhost:5432/codeflash
|
||||||
|
|
||||||
|
# Check API keys in database
|
||||||
|
docker exec codeflash psql postgresql://codeflash:codeflash@localhost:5432/codeflash \
|
||||||
|
-c "SELECT key, suffix FROM cf_api_keys;"
|
||||||
|
```
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Q: Do I need GitHub App configuration?**
|
||||||
|
A: No, not if you use `--no-pr` mode. GitHub integration is optional.
|
||||||
|
|
||||||
|
**Q: Do I need Stripe configuration?**
|
||||||
|
A: No, billing features are not required for on-premise deployments.
|
||||||
|
|
||||||
|
**Q: What AI providers are supported?**
|
||||||
|
A: Azure OpenAI, OpenAI, and Anthropic Claude. You only need one.
|
||||||
|
|
||||||
|
**Q: Can I use my own PostgreSQL database?**
|
||||||
|
A: Yes, set the `DATABASE_URL` environment variable.
|
||||||
|
|
||||||
|
**Q: What ports need to be accessible?**
|
||||||
|
A: For CLI usage, only ports 3001 (cf-api) and 8000 (aiservice) are required. Port 3000 (webapp) is for the web interface, and 5432 (PostgreSQL) is only if you want direct database access.
|
||||||
|
|
||||||
|
**Q: How much disk space is needed?**
|
||||||
|
A: ~5GB for the image, plus storage for your data (depends on usage).
|
||||||
|
|
||||||
|
**Q: How much memory is needed?**
|
||||||
|
A: Minimum 2GB RAM, recommended 4GB+ for optimal performance.
|
||||||
|
|
||||||
|
## Performance Notes
|
||||||
|
|
||||||
|
- **Container size:** ~5GB (includes all services and dependencies)
|
||||||
|
- **Startup time:** ~15-20 seconds for all services
|
||||||
|
- **Memory usage:** ~500MB-2GB (depending on workload)
|
||||||
|
- **CPU:** Works on both x86_64 and ARM64 (Apple Silicon)
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
deployment/onprem-simple/
|
||||||
|
├── Dockerfile.unifiedall # Main unified Docker image
|
||||||
|
├── supervisord.conf # Process manager configuration
|
||||||
|
├── startup.sh # Container startup script
|
||||||
|
├── init-db.sh # Database initialization script
|
||||||
|
├── .env.onprem.minimal # Minimal environment variables template
|
||||||
|
├── .dockerignore # Docker build exclusions
|
||||||
|
├── README.md # This file
|
||||||
|
├── TESTING.md # Testing guide
|
||||||
|
└── archive/ # Old/experimental files
|
||||||
|
├── old-dockerfiles/ # Previous Dockerfile attempts
|
||||||
|
├── old-compose/ # Old docker-compose files
|
||||||
|
└── old-scripts/ # Previous build scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- ✅ Container built and running
|
||||||
|
- ✅ Database initialized
|
||||||
|
- ✅ API key generated
|
||||||
|
- ✅ CLI configured
|
||||||
|
- 🚀 **Ready to optimize code!**
|
||||||
|
|
||||||
|
See `TESTING.md` for a complete testing guide with example workflows.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions:
|
||||||
|
- GitHub Issues: https://github.com/codeflash-ai/codeflash/issues
|
||||||
|
- Documentation: https://docs.codeflash.ai
|
||||||
550
deployment/onprem-simple/TESTING.md
Normal file
550
deployment/onprem-simple/TESTING.md
Normal file
|
|
@ -0,0 +1,550 @@
|
||||||
|
# Codeflash On-Premise Testing Guide
|
||||||
|
|
||||||
|
This guide walks through testing the Codeflash on-premise deployment step-by-step.
|
||||||
|
|
||||||
|
## Quick Test (5 minutes)
|
||||||
|
|
||||||
|
This is the fastest way to verify everything works:
|
||||||
|
|
||||||
|
### 1. Build and Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the image (from repository root)
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:latest .
|
||||||
|
|
||||||
|
# Run the container
|
||||||
|
docker run -d --name codeflash-test \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-azure-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-test-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
# Wait ~15 seconds for services to start
|
||||||
|
sleep 15
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Verify All Services Are Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check container status
|
||||||
|
docker ps | grep codeflash-test
|
||||||
|
|
||||||
|
# Check all services
|
||||||
|
docker exec codeflash-test supervisorctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
postgres RUNNING pid 40, uptime 0:00:15
|
||||||
|
aiservice RUNNING pid 41, uptime 0:00:15
|
||||||
|
cf-api RUNNING pid 42, uptime 0:00:15
|
||||||
|
cf-webapp RUNNING pid 43, uptime 0:00:15
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test Service Endpoints
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test cf-api
|
||||||
|
curl http://localhost:3001/cfapi/healthcheck
|
||||||
|
# Expected: {"status":"ok"}
|
||||||
|
|
||||||
|
# Test aiservice
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
# Expected: {"status":"healthy"}
|
||||||
|
|
||||||
|
# Test webapp
|
||||||
|
curl http://localhost:3000
|
||||||
|
# Expected: HTML content
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Get API Key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs codeflash-test | grep "Your API Key"
|
||||||
|
# Or
|
||||||
|
docker exec codeflash-test cat /app/API_KEY.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Test CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install CLI
|
||||||
|
pip install codeflash
|
||||||
|
|
||||||
|
# Configure environment
|
||||||
|
export CODEFLASH_API_KEY=cf-your-key-from-step-4
|
||||||
|
export CODEFLASH_AIS_SERVER=local
|
||||||
|
export CODEFLASH_CFAPI_SERVER=local
|
||||||
|
|
||||||
|
# Test connection
|
||||||
|
codeflash --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Test Optimization (Optional)
|
||||||
|
|
||||||
|
If you have a Python project to test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd your-python-project
|
||||||
|
codeflash --file path/to/file.py --function function_name --no-pr -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Cleanup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stop codeflash-test
|
||||||
|
docker rm codeflash-test
|
||||||
|
docker volume rm codeflash-test-data
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Detailed Testing Scenarios
|
||||||
|
|
||||||
|
### Scenario 1: Fresh Installation Test
|
||||||
|
|
||||||
|
Tests a brand new installation from scratch.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clean slate
|
||||||
|
docker stop codeflash-test 2>/dev/null || true
|
||||||
|
docker rm codeflash-test 2>/dev/null || true
|
||||||
|
docker volume rm codeflash-test-data 2>/dev/null || true
|
||||||
|
|
||||||
|
# Build
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:latest .
|
||||||
|
|
||||||
|
# Run
|
||||||
|
docker run -d --name codeflash-test \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-azure-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-test-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
# Wait for startup
|
||||||
|
sleep 20
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
docker logs codeflash-test
|
||||||
|
docker exec codeflash-test supervisorctl status
|
||||||
|
docker exec codeflash-test pg_isready -h localhost -p 5432 -U codeflash
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ All 4 services show "RUNNING"
|
||||||
|
- ✅ PostgreSQL is ready
|
||||||
|
- ✅ API key generated and saved
|
||||||
|
- ✅ No error messages in logs
|
||||||
|
|
||||||
|
### Scenario 2: Persistent Data Test
|
||||||
|
|
||||||
|
Tests that data persists across container restarts.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get initial API key
|
||||||
|
INITIAL_KEY=$(docker exec codeflash-test cat /app/API_KEY.txt)
|
||||||
|
echo "Initial API key: $INITIAL_KEY"
|
||||||
|
|
||||||
|
# Restart container
|
||||||
|
docker restart codeflash-test
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
# Get API key after restart
|
||||||
|
NEW_KEY=$(docker exec codeflash-test cat /app/API_KEY.txt)
|
||||||
|
echo "API key after restart: $NEW_KEY"
|
||||||
|
|
||||||
|
# Compare
|
||||||
|
if [ "$INITIAL_KEY" = "$NEW_KEY" ]; then
|
||||||
|
echo "✅ Data persisted correctly"
|
||||||
|
else
|
||||||
|
echo "❌ Data did not persist"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ API key remains the same after restart
|
||||||
|
- ✅ All services restart successfully
|
||||||
|
- ✅ Database data is intact
|
||||||
|
|
||||||
|
### Scenario 3: Service Restart Test
|
||||||
|
|
||||||
|
Tests individual service restarts.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restart cf-api
|
||||||
|
docker exec codeflash-test supervisorctl restart cf-api
|
||||||
|
sleep 5
|
||||||
|
curl http://localhost:3001/cfapi/healthcheck
|
||||||
|
|
||||||
|
# Restart aiservice
|
||||||
|
docker exec codeflash-test supervisorctl restart aiservice
|
||||||
|
sleep 5
|
||||||
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
|
# Restart cf-webapp
|
||||||
|
docker exec codeflash-test supervisorctl restart cf-webapp
|
||||||
|
sleep 5
|
||||||
|
curl http://localhost:3000
|
||||||
|
|
||||||
|
# Check all services
|
||||||
|
docker exec codeflash-test supervisorctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ Each service restarts without errors
|
||||||
|
- ✅ Endpoints respond after restart
|
||||||
|
- ✅ No cascading failures
|
||||||
|
|
||||||
|
### Scenario 4: Database Test
|
||||||
|
|
||||||
|
Tests database connectivity and data.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check PostgreSQL is running
|
||||||
|
docker exec codeflash-test pg_isready -h localhost -p 5432 -U codeflash
|
||||||
|
|
||||||
|
# Check database exists
|
||||||
|
docker exec codeflash-test psql postgresql://codeflash:codeflash@localhost:5432/codeflash \
|
||||||
|
-c "\l" | grep codeflash
|
||||||
|
|
||||||
|
# Check tables exist
|
||||||
|
docker exec codeflash-test psql postgresql://codeflash:codeflash@localhost:5432/codeflash \
|
||||||
|
-c "\dt" | head -10
|
||||||
|
|
||||||
|
# Check user exists
|
||||||
|
docker exec codeflash-test psql postgresql://codeflash:codeflash@localhost:5432/codeflash \
|
||||||
|
-c "SELECT * FROM users;"
|
||||||
|
|
||||||
|
# Check API key exists
|
||||||
|
docker exec codeflash-test psql postgresql://codeflash:codeflash@localhost:5432/codeflash \
|
||||||
|
-c "SELECT key, suffix FROM cf_api_keys;"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ Database `codeflash` exists
|
||||||
|
- ✅ All migrations applied (36+ tables)
|
||||||
|
- ✅ User created
|
||||||
|
- ✅ API key stored
|
||||||
|
|
||||||
|
### Scenario 5: CLI Integration Test
|
||||||
|
|
||||||
|
Full end-to-end test with a real Python file.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create test project
|
||||||
|
mkdir -p /tmp/codeflash-test-project
|
||||||
|
cd /tmp/codeflash-test-project
|
||||||
|
|
||||||
|
# Create a simple Python file
|
||||||
|
cat > test.py << 'EOF'
|
||||||
|
def fibonacci(n):
|
||||||
|
"""Calculate fibonacci number recursively (slow)."""
|
||||||
|
if n <= 1:
|
||||||
|
return n
|
||||||
|
return fibonacci(n - 1) + fibonacci(n - 2)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(fibonacci(10))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Get API key
|
||||||
|
export CODEFLASH_API_KEY=$(docker exec codeflash-test cat /app/API_KEY.txt)
|
||||||
|
export CODEFLASH_AIS_SERVER=local
|
||||||
|
export CODEFLASH_CFAPI_SERVER=local
|
||||||
|
|
||||||
|
# Install CLI
|
||||||
|
pip install codeflash
|
||||||
|
|
||||||
|
# Run optimization
|
||||||
|
codeflash --file test.py --function fibonacci --no-pr -v
|
||||||
|
|
||||||
|
# Check if file was modified
|
||||||
|
git diff test.py 2>/dev/null || echo "File modified (no git)"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ CLI connects successfully
|
||||||
|
- ✅ Optimization completes without errors
|
||||||
|
- ✅ Function is optimized (or determined not optimizable)
|
||||||
|
- ✅ Test file shows improvements
|
||||||
|
|
||||||
|
### Scenario 6: Port Conflict Test
|
||||||
|
|
||||||
|
Tests behavior when ports are already in use.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Try to run second container (should fail)
|
||||||
|
docker run -d --name codeflash-test-2 \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
codeflash/unified:latest 2>&1 | grep "address already in use"
|
||||||
|
|
||||||
|
# Run with different ports (should succeed)
|
||||||
|
docker run -d --name codeflash-test-2 \
|
||||||
|
-e AZURE_OPENAI_API_KEY=your-key \
|
||||||
|
-p 15432:5432 -p 18000:8000 -p 13001:3001 -p 13000:3000 \
|
||||||
|
-v codeflash-test-2-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
sleep 15
|
||||||
|
docker exec codeflash-test-2 supervisorctl status
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
docker stop codeflash-test-2
|
||||||
|
docker rm codeflash-test-2
|
||||||
|
docker volume rm codeflash-test-2-data
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ Second container with same ports fails gracefully
|
||||||
|
- ✅ Second container with different ports works
|
||||||
|
- ✅ Both containers can run simultaneously
|
||||||
|
|
||||||
|
### Scenario 7: Environment Variable Test
|
||||||
|
|
||||||
|
Tests various environment variable configurations.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test with minimal config
|
||||||
|
docker run -d --name codeflash-minimal \
|
||||||
|
-e AZURE_OPENAI_API_KEY=test-key \
|
||||||
|
-p 25432:5432 -p 28000:8000 -p 23001:3001 -p 23000:3000 \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
docker logs codeflash-minimal | grep "Generated SECRET_KEY"
|
||||||
|
docker logs codeflash-minimal | grep "API Key:"
|
||||||
|
|
||||||
|
# Test with full config
|
||||||
|
docker run -d --name codeflash-full \
|
||||||
|
-e AZURE_OPENAI_API_KEY=test-key \
|
||||||
|
-e SECRET_KEY=my-custom-secret \
|
||||||
|
-e NEXT_PUBLIC_APP_URL=http://custom.domain:3000 \
|
||||||
|
-e WEBAPP_URL=http://custom.domain:3000 \
|
||||||
|
-p 35432:5432 -p 38000:8000 -p 33001:3001 -p 33000:3000 \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
docker logs codeflash-full | grep -v "Generated SECRET_KEY"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
docker stop codeflash-minimal codeflash-full
|
||||||
|
docker rm codeflash-minimal codeflash-full
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ Minimal config works with auto-generated values
|
||||||
|
- ✅ Full config respects custom values
|
||||||
|
- ✅ No required variables missing
|
||||||
|
|
||||||
|
### Scenario 8: Upgrade Test
|
||||||
|
|
||||||
|
Tests upgrading from one version to another.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run old version
|
||||||
|
docker run -d --name codeflash-old \
|
||||||
|
-e AZURE_OPENAI_API_KEY=test-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-upgrade-test:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
OLD_KEY=$(docker exec codeflash-old cat /app/API_KEY.txt)
|
||||||
|
|
||||||
|
# Stop old container
|
||||||
|
docker stop codeflash-old
|
||||||
|
docker rm codeflash-old
|
||||||
|
|
||||||
|
# Rebuild image (simulating new version)
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:latest .
|
||||||
|
|
||||||
|
# Run new version with same volume
|
||||||
|
docker run -d --name codeflash-new \
|
||||||
|
-e AZURE_OPENAI_API_KEY=test-key \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-upgrade-test:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
NEW_KEY=$(docker exec codeflash-new cat /app/API_KEY.txt)
|
||||||
|
|
||||||
|
# Compare
|
||||||
|
if [ "$OLD_KEY" = "$NEW_KEY" ]; then
|
||||||
|
echo "✅ Upgrade successful - data preserved"
|
||||||
|
else
|
||||||
|
echo "❌ Upgrade failed - data lost"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
docker stop codeflash-new
|
||||||
|
docker rm codeflash-new
|
||||||
|
docker volume rm codeflash-upgrade-test
|
||||||
|
```
|
||||||
|
|
||||||
|
**Success criteria:**
|
||||||
|
- ✅ New version starts successfully
|
||||||
|
- ✅ Data from old version is preserved
|
||||||
|
- ✅ API key remains the same
|
||||||
|
- ✅ No data migration issues
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoring and Debugging
|
||||||
|
|
||||||
|
### Watch All Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Follow all logs
|
||||||
|
docker logs -f codeflash-test
|
||||||
|
|
||||||
|
# Filter specific service
|
||||||
|
docker logs codeflash-test | grep "cf-api"
|
||||||
|
docker logs codeflash-test | grep "aiservice"
|
||||||
|
docker logs codeflash-test | grep "postgres"
|
||||||
|
docker logs codeflash-test | grep "webapp"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Resource Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Container stats
|
||||||
|
docker stats codeflash-test
|
||||||
|
|
||||||
|
# Disk usage
|
||||||
|
docker system df
|
||||||
|
du -sh /var/lib/docker/volumes/codeflash-test-data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Debugging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Access container shell
|
||||||
|
docker exec -it codeflash-test bash
|
||||||
|
|
||||||
|
# Check service logs inside container
|
||||||
|
docker exec codeflash-test tail -f /var/log/supervisor/cf-api-stdout.log
|
||||||
|
docker exec codeflash-test tail -f /var/log/supervisor/aiservice-stdout.log
|
||||||
|
docker exec codeflash-test tail -f /var/log/supervisor/postgres-stdout.log
|
||||||
|
docker exec codeflash-test tail -f /var/log/supervisor/webapp-stdout.log
|
||||||
|
|
||||||
|
# Check process tree
|
||||||
|
docker exec codeflash-test ps auxf
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Test Failures
|
||||||
|
|
||||||
|
### Container won't start
|
||||||
|
```bash
|
||||||
|
docker logs codeflash-test | grep -i error
|
||||||
|
docker logs codeflash-test | grep -i fail
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service shows FATAL
|
||||||
|
```bash
|
||||||
|
docker exec codeflash-test supervisorctl tail cf-api
|
||||||
|
docker exec codeflash-test supervisorctl tail aiservice
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL not ready
|
||||||
|
```bash
|
||||||
|
docker exec codeflash-test pg_isready
|
||||||
|
docker logs codeflash-test | grep postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### API key not generated
|
||||||
|
```bash
|
||||||
|
docker logs codeflash-test | grep "API Key"
|
||||||
|
docker exec codeflash-test ls -la /app/API_KEY.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Automated Test Script
|
||||||
|
|
||||||
|
Save this as `test-deployment.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Starting Codeflash deployment test..."
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
echo "🧹 Cleaning up old test containers..."
|
||||||
|
docker stop codeflash-test 2>/dev/null || true
|
||||||
|
docker rm codeflash-test 2>/dev/null || true
|
||||||
|
docker volume rm codeflash-test-data 2>/dev/null || true
|
||||||
|
|
||||||
|
# Build
|
||||||
|
echo "🔨 Building image..."
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unifiedall -t codeflash/unified:test .
|
||||||
|
|
||||||
|
# Run
|
||||||
|
echo "🏃 Running container..."
|
||||||
|
docker run -d --name codeflash-test \
|
||||||
|
-e AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY:-test-key} \
|
||||||
|
-p 5432:5432 -p 8000:8000 -p 3001:3001 -p 3000:3000 \
|
||||||
|
-v codeflash-test-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:test
|
||||||
|
|
||||||
|
# Wait
|
||||||
|
echo "⏳ Waiting for services to start..."
|
||||||
|
sleep 20
|
||||||
|
|
||||||
|
# Test
|
||||||
|
echo "🔍 Testing services..."
|
||||||
|
docker exec codeflash-test supervisorctl status | grep RUNNING || (echo "❌ Services not running" && exit 1)
|
||||||
|
curl -f http://localhost:3001/cfapi/healthcheck || (echo "❌ cf-api not responding" && exit 1)
|
||||||
|
curl -f http://localhost:8000/health || (echo "❌ aiservice not responding" && exit 1)
|
||||||
|
docker exec codeflash-test pg_isready || (echo "❌ PostgreSQL not ready" && exit 1)
|
||||||
|
|
||||||
|
# Get API key
|
||||||
|
echo "🔑 Retrieving API key..."
|
||||||
|
API_KEY=$(docker exec codeflash-test cat /app/API_KEY.txt)
|
||||||
|
echo "API Key: $API_KEY"
|
||||||
|
|
||||||
|
echo "✅ All tests passed!"
|
||||||
|
echo ""
|
||||||
|
echo "To clean up: docker stop codeflash-test && docker rm codeflash-test && docker volume rm codeflash-test-data"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make it executable and run:
|
||||||
|
```bash
|
||||||
|
chmod +x test-deployment.sh
|
||||||
|
./test-deployment.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Benchmarks
|
||||||
|
|
||||||
|
Expected performance metrics:
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Build time | 5-10 minutes |
|
||||||
|
| Startup time | 15-20 seconds |
|
||||||
|
| Container size | ~5GB |
|
||||||
|
| Memory usage (idle) | ~500MB |
|
||||||
|
| Memory usage (active) | ~1-2GB |
|
||||||
|
| CPU usage (idle) | <5% |
|
||||||
|
| CPU usage (optimizing) | 50-100% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
After successful testing:
|
||||||
|
1. Update to your actual AI provider keys
|
||||||
|
2. Configure custom domain/URLs if needed
|
||||||
|
3. Set up monitoring and backups
|
||||||
|
4. Deploy to production environment
|
||||||
|
5. Document your specific configuration
|
||||||
|
|
||||||
|
For production deployment best practices, see the main README.md.
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: codeflash-postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: codeflash
|
||||||
|
POSTGRES_USER: codeflash
|
||||||
|
POSTGRES_PASSWORD: codeflash
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U codeflash"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
db-init:
|
||||||
|
image: codeflash/cf-api:latest
|
||||||
|
container_name: codeflash-db-init
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://codeflash:codeflash@postgres:5432/codeflash
|
||||||
|
command: >
|
||||||
|
sh -c "
|
||||||
|
echo 'Running Prisma migrations...' &&
|
||||||
|
cd /app/common &&
|
||||||
|
npx prisma migrate deploy &&
|
||||||
|
echo 'Checking for existing users...' &&
|
||||||
|
USER_COUNT=$$(psql postgresql://codeflash:codeflash@postgres:5432/codeflash -t -c 'SELECT COUNT(*) FROM users;' 2>/dev/null | tr -d ' ' || echo '0') &&
|
||||||
|
if [ \"$$USER_COUNT\" = \"0\" ]; then
|
||||||
|
echo 'Creating default user and API key...' &&
|
||||||
|
API_KEY=\"cf_$$(openssl rand -hex 32)\" &&
|
||||||
|
SUFFIX=\"$${API_KEY: -4}\" &&
|
||||||
|
psql postgresql://codeflash:codeflash@postgres:5432/codeflash <<-EOSQL &&
|
||||||
|
INSERT INTO users (user_id, github_username, email, name, onboarding_completed, created_at)
|
||||||
|
VALUES ('local|default-user', 'codeflash-user', 'user@codeflash.local', 'Default User', true, NOW())
|
||||||
|
ON CONFLICT (user_id) DO NOTHING;
|
||||||
|
INSERT INTO cf_api_keys (key, suffix, name, user_id, tier, created_at)
|
||||||
|
VALUES ('$$API_KEY', '$$SUFFIX', 'Default API Key', 'local|default-user', 'free', NOW());
|
||||||
|
EOSQL
|
||||||
|
echo '' &&
|
||||||
|
echo '======================================' &&
|
||||||
|
echo ' CODEFLASH API KEY CREATED' &&
|
||||||
|
echo '======================================' &&
|
||||||
|
echo '' &&
|
||||||
|
echo \"$$API_KEY\" &&
|
||||||
|
echo '' &&
|
||||||
|
echo 'Add to cli/codeflash/.env:' &&
|
||||||
|
echo \"CODEFLASH_API_KEY=$$API_KEY\" &&
|
||||||
|
echo 'CODEFLASH_AIS_SERVER=local' &&
|
||||||
|
echo 'CODEFLASH_CFAPI_SERVER=local' &&
|
||||||
|
echo '' &&
|
||||||
|
echo '======================================';
|
||||||
|
else
|
||||||
|
echo 'Users exist. To get API key run:' &&
|
||||||
|
echo 'docker exec codeflash-postgres psql -U codeflash -d codeflash -c \"SELECT key FROM cf_api_keys LIMIT 1;\"';
|
||||||
|
fi &&
|
||||||
|
echo 'Database ready!'
|
||||||
|
"
|
||||||
|
restart: "no"
|
||||||
|
|
||||||
|
aiservice:
|
||||||
|
image: codeflash/aiservice:latest
|
||||||
|
container_name: codeflash-aiservice
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
db-init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://codeflash:codeflash@postgres:5432/codeflash
|
||||||
|
SECRET_KEY: development-secret-key
|
||||||
|
OPENAI_API_TYPE: azure
|
||||||
|
AZURE_OPENAI_API_KEY: ${AZURE_OPENAI_API_KEY}
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
|
ENVIRONMENT: DEVELOPMENT
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
|
||||||
|
cf-api:
|
||||||
|
image: codeflash/cf-api:latest
|
||||||
|
container_name: codeflash-cf-api
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
db-init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
aiservice:
|
||||||
|
condition: service_started
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://codeflash:codeflash@postgres:5432/codeflash
|
||||||
|
AISERVICE_URL: http://aiservice:8000
|
||||||
|
GH_APP_ID: 800528
|
||||||
|
GH_APP_USER_ID: 148906541
|
||||||
|
GH_APP_WEBHOOK_SECRET: dev-webhook-secret
|
||||||
|
SECRET_KEY: development-secret-key
|
||||||
|
NODE_ENV: local
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-codeflash}
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-codeflash}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
aiservice:
|
||||||
|
image: codeflash/aiservice:latest
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-codeflash}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-codeflash}
|
||||||
|
OPENAI_API_KEY: ${OPENAI_API_KEY}
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
|
SECRET_KEY: ${DJANGO_SECRET_KEY}
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
cf-api:
|
||||||
|
image: codeflash/cf-api:latest
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-codeflash}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-codeflash}
|
||||||
|
GH_APP_ID: ${GH_APP_ID}
|
||||||
|
GH_APP_PRIVATE_KEY: ${GH_APP_PRIVATE_KEY}
|
||||||
|
GH_APP_WEBHOOK_SECRET: ${GH_APP_WEBHOOK_SECRET}
|
||||||
|
AISERVICE_URL: http://aiservice:8000
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- aiservice
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
cf-webapp:
|
||||||
|
image: codeflash/cf-webapp:latest
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-codeflash}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-codeflash}
|
||||||
|
CODEFLASH_CFAPI_URL: http://cf-api:3001
|
||||||
|
AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID}
|
||||||
|
AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET}
|
||||||
|
AUTH0_ISSUER_BASE_URL: ${AUTH0_ISSUER_BASE_URL}
|
||||||
|
AUTH0_SECRET: ${AUTH0_SECRET}
|
||||||
|
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL}
|
||||||
|
depends_on:
|
||||||
|
- cf-api
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install uv
|
||||||
|
RUN pip install uv
|
||||||
|
|
||||||
|
# Copy entire aiservice directory
|
||||||
|
COPY aiservice ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN uv sync
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV ENVIRONMENT=PRODUCTION
|
||||||
|
ENV PORT=8000
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Use the start script that references gunicorn.conf.py
|
||||||
|
CMD ["uv", "run", "gunicorn", "-c", "gunicorn.conf.py", "aiservice.asgi:application", \
|
||||||
|
"--bind", "0.0.0.0:8000", \
|
||||||
|
"--timeout", "600", \
|
||||||
|
"--workers", "2"]
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy both cf-api and common
|
||||||
|
COPY cf-api ./cf-api
|
||||||
|
COPY common ./common
|
||||||
|
|
||||||
|
# Build common package first (since cf-api depends on it)
|
||||||
|
WORKDIR /build/common
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# Install ALL dependencies for cf-api (including dev dependencies)
|
||||||
|
WORKDIR /build/cf-api
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Replace the common package from registry with local build
|
||||||
|
RUN rm -rf node_modules/@codeflash-ai/common && \
|
||||||
|
cp -r /build/common node_modules/@codeflash-ai/
|
||||||
|
|
||||||
|
# Clean dist folder before build to avoid nested dist directories
|
||||||
|
RUN rm -rf dist
|
||||||
|
|
||||||
|
# Build TypeScript
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the built files
|
||||||
|
COPY --from=0 /build/cf-api/dist ./dist
|
||||||
|
COPY --from=0 /build/cf-api/package.json ./package.json
|
||||||
|
COPY --from=0 /build/cf-api/package-lock.json ./package-lock.json
|
||||||
|
COPY --from=0 /build/cf-api/resend ./resend
|
||||||
|
COPY --from=0 /build/cf-api/github ./github
|
||||||
|
|
||||||
|
# Copy common package to parent directory (matching Azure structure)
|
||||||
|
COPY --from=0 /build/common ../common
|
||||||
|
|
||||||
|
# Copy already installed node_modules from build stage
|
||||||
|
COPY --from=0 /build/cf-api/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy node_modules into dist to match Azure deployment structure
|
||||||
|
# Use -L to follow symlinks and avoid broken nested structures
|
||||||
|
RUN cp -rL node_modules dist/ 2>/dev/null || cp -r node_modules dist/
|
||||||
|
|
||||||
|
EXPOSE 3001
|
||||||
|
|
||||||
|
CMD ["npm", "start"]
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
# Stage 1: Build cf-api and common
|
||||||
|
FROM node:20-alpine AS js-builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy JavaScript projects
|
||||||
|
COPY js/cf-api ./cf-api
|
||||||
|
COPY js/common ./common
|
||||||
|
|
||||||
|
# Build common package first
|
||||||
|
WORKDIR /build/common
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# Build cf-api
|
||||||
|
WORKDIR /build/cf-api
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Replace common package from registry with local build
|
||||||
|
RUN rm -rf node_modules/@codeflash-ai/common && \
|
||||||
|
cp -r /build/common node_modules/@codeflash-ai/
|
||||||
|
|
||||||
|
# Clean and build cf-api
|
||||||
|
RUN rm -rf dist && npm run build
|
||||||
|
|
||||||
|
# Stage 2: Build aiservice
|
||||||
|
FROM python:3.12-slim AS python-builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install uv
|
||||||
|
RUN pip install uv
|
||||||
|
|
||||||
|
# Copy and build aiservice
|
||||||
|
COPY django/aiservice ./aiservice
|
||||||
|
WORKDIR /build/aiservice
|
||||||
|
RUN uv sync
|
||||||
|
|
||||||
|
# Stage 3: Final unified image
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install Python, PostgreSQL client, and supervisor
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
postgresql15 \
|
||||||
|
postgresql15-client \
|
||||||
|
supervisor \
|
||||||
|
bash \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# Install Python dependencies globally
|
||||||
|
RUN pip3 install --break-system-packages uv
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy cf-api from js-builder
|
||||||
|
COPY --from=js-builder /build/cf-api/dist ./cf-api/dist
|
||||||
|
COPY --from=js-builder /build/cf-api/package.json ./cf-api/package.json
|
||||||
|
COPY --from=js-builder /build/cf-api/package-lock.json ./cf-api/package-lock.json
|
||||||
|
COPY --from=js-builder /build/cf-api/node_modules ./cf-api/node_modules
|
||||||
|
COPY --from=js-builder /build/cf-api/resend ./cf-api/resend
|
||||||
|
COPY --from=js-builder /build/cf-api/github ./cf-api/github
|
||||||
|
COPY --from=js-builder /build/common ./common
|
||||||
|
|
||||||
|
# Copy node_modules into dist for ESM resolution
|
||||||
|
RUN cd cf-api && cp -rL node_modules dist/ 2>/dev/null || cp -r node_modules dist/
|
||||||
|
|
||||||
|
# Copy aiservice from python-builder
|
||||||
|
COPY --from=python-builder /build/aiservice ./aiservice
|
||||||
|
|
||||||
|
# Create PostgreSQL data directory
|
||||||
|
RUN mkdir -p /var/lib/postgresql/data /var/run/postgresql && \
|
||||||
|
chown -R postgres:postgres /var/lib/postgresql /var/run/postgresql
|
||||||
|
|
||||||
|
# Copy configuration files
|
||||||
|
COPY deployment/onprem-simple/supervisord.conf /etc/supervisord.conf
|
||||||
|
COPY deployment/onprem-simple/init-db.sh /app/init-db.sh
|
||||||
|
COPY deployment/onprem-simple/startup.sh /app/startup.sh
|
||||||
|
|
||||||
|
RUN chmod +x /app/init-db.sh /app/startup.sh
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
EXPOSE 5432 8000 3001
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PGDATA=/var/lib/postgresql/data
|
||||||
|
ENV PATH="/var/lib/postgresql/bin:${PATH}"
|
||||||
|
|
||||||
|
# Start supervisor
|
||||||
|
CMD ["/app/startup.sh"]
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Unified Codeflash Container - Using Pre-built Images
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install Python, PostgreSQL, and supervisor
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
postgresql15 \
|
||||||
|
postgresql15-client \
|
||||||
|
supervisor \
|
||||||
|
bash \
|
||||||
|
openssl \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# Install Python uv
|
||||||
|
RUN pip3 install --break-system-packages uv
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy cf-api from pre-built image
|
||||||
|
COPY --from=codeflash/cf-api:latest /app /app/cf-api
|
||||||
|
COPY --from=codeflash/cf-api:latest /common /common
|
||||||
|
|
||||||
|
# Copy aiservice from pre-built image
|
||||||
|
COPY --from=codeflash/aiservice:latest /app /app/aiservice
|
||||||
|
|
||||||
|
# Create PostgreSQL data directory with correct permissions
|
||||||
|
RUN mkdir -p /var/lib/postgresql/data /var/run/postgresql && \
|
||||||
|
chown -R postgres:postgres /var/lib/postgresql /var/run/postgresql
|
||||||
|
|
||||||
|
# Copy configuration files
|
||||||
|
COPY deployment/onprem-simple/supervisord.conf /etc/supervisord.conf
|
||||||
|
COPY deployment/onprem-simple/init-db.sh /app/init-db.sh
|
||||||
|
COPY deployment/onprem-simple/startup.sh /app/startup.sh
|
||||||
|
|
||||||
|
RUN chmod +x /app/init-db.sh /app/startup.sh
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
EXPOSE 5432 8000 3001
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PGDATA=/var/lib/postgresql/data
|
||||||
|
ENV PATH="/var/lib/postgresql/bin:${PATH}"
|
||||||
|
|
||||||
|
# Start supervisor
|
||||||
|
CMD ["/app/startup.sh"]
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy both cf-webapp and common
|
||||||
|
COPY cf-webapp ./cf-webapp
|
||||||
|
COPY common ./common
|
||||||
|
|
||||||
|
# Install ALL dependencies for build
|
||||||
|
WORKDIR /build/cf-webapp
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Build Next.js
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy entire built application (simpler approach)
|
||||||
|
COPY --from=0 /build/cf-webapp ./
|
||||||
|
COPY --from=0 /build/common ../common
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "start"]
|
||||||
66
deployment/onprem-simple/archive/old-scripts/REBUILD-AND-TEST.sh
Executable file
66
deployment/onprem-simple/archive/old-scripts/REBUILD-AND-TEST.sh
Executable file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo " Codeflash Complete Rebuild and Test"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
cd /Users/saga4/orgs/codeflash-internal
|
||||||
|
|
||||||
|
echo "Step 1: Stopping and removing old container..."
|
||||||
|
docker stop codeflash-unified 2>/dev/null || true
|
||||||
|
docker rm codeflash-unified 2>/dev/null || true
|
||||||
|
echo "✓ Old container removed"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Step 2: Rebuilding image..."
|
||||||
|
echo "This will take 5-10 minutes..."
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unified-selfcontained -t codeflash/unified:latest .
|
||||||
|
echo "✓ Image rebuilt"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Step 3: Starting new container..."
|
||||||
|
docker run -d --name codeflash-unified \
|
||||||
|
-e OPENAI_API_TYPE=azure \
|
||||||
|
-e AZURE_OPENAI_API_KEY=dabd9790e9a54558b4ceafdd74425904 \
|
||||||
|
-e ANTHROPIC_API_KEY=sk-ant-api03-E85T16Zy7bGRo1BxVdFUJG_JRMVdMaePuLUJMFO-EQHqI17z0lWMYRHaHKUU47XeNNwZNHl86h1p-Yoq5vVgzg \
|
||||||
|
-e SECRET_KEY=bla \
|
||||||
|
-e NODE_ENV=local \
|
||||||
|
-e GH_APP_ID=800528 \
|
||||||
|
-e GH_APP_USER_ID=148906541 \
|
||||||
|
-e GH_APP_WEBHOOK_SECRET=dev-webhook-secret-2pjGGmaNy2gyEY4o3aU \
|
||||||
|
-e STRIPE_SECRET_KEY=sk_test_51Pap5bRrNDfNWAM0DpQb8D8sCSYxG9aFzc9N5wXN8pVT0fXLQwrJgZEZq1aRoQ9VZgVK7pXKp5aWQZYW7vXKp00aZX5aWQ \
|
||||||
|
-p 5432:5432 \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-p 3001:3001 \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
echo "✓ Container started"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Step 4: Waiting for services to start (30 seconds)..."
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
echo "Step 5: Checking service status..."
|
||||||
|
docker exec codeflash-unified supervisorctl status
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Step 6: Getting API key..."
|
||||||
|
API_KEY=$(docker exec codeflash-unified psql postgresql://codeflash:codeflash@localhost:5432/codeflash -t -c "SELECT 'cf-' || key FROM cf_api_keys LIMIT 1;" | tr -d ' ')
|
||||||
|
echo "API Key: $API_KEY"
|
||||||
|
|
||||||
|
echo "Step 7: Testing CLI..."
|
||||||
|
export CODEFLASH_API_KEY=$API_KEY
|
||||||
|
export CODEFLASH_AIS_SERVER=local
|
||||||
|
export CODEFLASH_CFAPI_SERVER=local
|
||||||
|
|
||||||
|
cd /Users/saga4/orgs/optimize-me
|
||||||
|
codeflash --file src/math/computation.py --function gcd_recursive --no-pr -v
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo " Test Complete!"
|
||||||
|
echo "=========================================="
|
||||||
50
deployment/onprem-simple/archive/old-scripts/build-images.sh
Executable file
50
deployment/onprem-simple/archive/old-scripts/build-images.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Simple script to build all images
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Building Codeflash Docker images..."
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
# Check if Docker is running
|
||||||
|
if ! docker info > /dev/null 2>&1; then
|
||||||
|
echo "ERROR: Docker is not running. Please start Docker Desktop and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
# Build cf-api
|
||||||
|
echo ""
|
||||||
|
echo "===================="
|
||||||
|
echo "Building cf-api..."
|
||||||
|
echo "===================="
|
||||||
|
cd js
|
||||||
|
docker build -t codeflash/cf-api:latest -f ../deployment/onprem-simple/Dockerfile.cfapi cf-api/
|
||||||
|
|
||||||
|
# Build cf-webapp
|
||||||
|
echo ""
|
||||||
|
echo "===================="
|
||||||
|
echo "Building cf-webapp..."
|
||||||
|
echo "===================="
|
||||||
|
docker build -t codeflash/cf-webapp:latest -f ../deployment/onprem-simple/Dockerfile.webapp cf-webapp/
|
||||||
|
|
||||||
|
# Build aiservice
|
||||||
|
echo ""
|
||||||
|
echo "===================="
|
||||||
|
echo "Building aiservice..."
|
||||||
|
echo "===================="
|
||||||
|
cd ../django
|
||||||
|
docker build -t codeflash/aiservice:latest -f ../deployment/onprem-simple/Dockerfile.aiservice aiservice/
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ All images built successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Images created:"
|
||||||
|
docker images | grep codeflash
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Test locally: cd $SCRIPT_DIR && docker-compose up -d"
|
||||||
|
echo "2. Push to registry: docker push codeflash/cf-api:latest"
|
||||||
61
deployment/onprem-simple/archive/old-scripts/build.sh
Normal file
61
deployment/onprem-simple/archive/old-scripts/build.sh
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "Codeflash Unified Container Builder"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Get the repository root (2 levels up from this script)
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
echo "Repository root: $REPO_ROOT"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if we should skip individual builds (for faster rebuilds)
|
||||||
|
SKIP_SERVICE_BUILDS=${SKIP_SERVICE_BUILDS:-false}
|
||||||
|
|
||||||
|
if [ "$SKIP_SERVICE_BUILDS" = "false" ]; then
|
||||||
|
echo "Step 1/3: Building aiservice image..."
|
||||||
|
echo "--------------------------------------"
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.aiservice -t codeflash/aiservice:latest .
|
||||||
|
echo "✓ aiservice image built successfully"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Step 2/3: Building cf-api image..."
|
||||||
|
echo "--------------------------------------"
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.cfapi -t codeflash/cf-api:latest .
|
||||||
|
echo "✓ cf-api image built successfully"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "Skipping individual service builds (SKIP_SERVICE_BUILDS=true)"
|
||||||
|
echo "Using existing codeflash/aiservice:latest and codeflash/cf-api:latest"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Step 3/3: Building unified container..."
|
||||||
|
echo "--------------------------------------"
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unified-simple -t codeflash/unified:latest .
|
||||||
|
echo "✓ unified container built successfully"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "✓ Build Complete!"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
echo "Image: codeflash/unified:latest"
|
||||||
|
echo ""
|
||||||
|
echo "To run the container, use:"
|
||||||
|
echo " docker run -d --name codeflash \\"
|
||||||
|
echo " --env-file .env \\"
|
||||||
|
echo " -p 5432:5432 \\"
|
||||||
|
echo " -p 8000:8000 \\"
|
||||||
|
echo " -p 3001:3001 \\"
|
||||||
|
echo " -v codeflash-data:/var/lib/postgresql/data \\"
|
||||||
|
echo " codeflash/unified:latest"
|
||||||
|
echo ""
|
||||||
|
echo "Or see deployment/onprem-simple/README.md for detailed instructions."
|
||||||
|
echo ""
|
||||||
128
deployment/onprem-simple/archive/old-scripts/run-fresh.sh
Normal file
128
deployment/onprem-simple/archive/old-scripts/run-fresh.sh
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo " Codeflash Fresh Deployment"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Get repository root
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
echo "Repository: $REPO_ROOT"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 1: Clean up
|
||||||
|
echo "Step 1: Cleaning up existing containers..."
|
||||||
|
echo "-------------------------------------------"
|
||||||
|
docker stop codeflash-unified 2>/dev/null && echo "✓ Stopped existing container" || echo "→ No existing container to stop"
|
||||||
|
docker rm codeflash-unified 2>/dev/null && echo "✓ Removed existing container" || echo "→ No existing container to remove"
|
||||||
|
docker volume rm codeflash-data 2>/dev/null && echo "✓ Removed data volume" || echo "→ No existing data volume to remove"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 2: Build
|
||||||
|
echo "Step 2: Building unified container..."
|
||||||
|
echo "-------------------------------------------"
|
||||||
|
echo "This will take 5-10 minutes on first build..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
docker build -f deployment/onprem-simple/Dockerfile.unified-selfcontained \
|
||||||
|
-t codeflash/unified:latest .
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Build complete!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 3: Run
|
||||||
|
echo "Step 3: Starting container..."
|
||||||
|
echo "-------------------------------------------"
|
||||||
|
|
||||||
|
docker run -d --name codeflash-unified \
|
||||||
|
-e OPENAI_API_TYPE=azure \
|
||||||
|
-e AZURE_OPENAI_API_KEY=dabd9790e9a54558b4ceafdd74425904 \
|
||||||
|
-e ANTHROPIC_API_KEY=sk-ant-api03-E85T16Zy7bGRo1BxVdFUJG_JRMVdMaePuLUJMFO-EQHqI17z0lWMYRHaHKUU47XeNNwZNHl86h1p-Yoq5vVgzg \
|
||||||
|
-e SECRET_KEY=bla \
|
||||||
|
-e NODE_ENV=local \
|
||||||
|
-e GH_APP_ID=800528 \
|
||||||
|
-e GH_APP_USER_ID=148906541 \
|
||||||
|
-e GH_APP_WEBHOOK_SECRET=dev-webhook-secret-2pjGGmaNy2gyEY4o3aU \
|
||||||
|
-e STRIPE_SECRET_KEY=sk_test_51Pap5bRrNDfNWAM0DpQb8D8sCSYxG9aFzc9N5wXN8pVT0fXLQwrJgZEZq1aRoQ9VZgVK7pXKp5aWQZYW7vXKp00aZX5aWQ \
|
||||||
|
-p 5432:5432 \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-p 3001:3001 \
|
||||||
|
-v codeflash-data:/var/lib/postgresql/data \
|
||||||
|
codeflash/unified:latest
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Container started!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 4: Wait for services to start
|
||||||
|
echo "Step 4: Waiting for services to start..."
|
||||||
|
echo "-------------------------------------------"
|
||||||
|
echo "This may take 15-30 seconds..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Wait for the API key file to be created (indicates initialization is complete)
|
||||||
|
for i in {1..30}; do
|
||||||
|
if docker exec codeflash-unified test -f /app/API_KEY.txt 2>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " Waiting for database initialization... ($i/30)"
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 5: Verify services
|
||||||
|
echo "Step 5: Verifying services..."
|
||||||
|
echo "-------------------------------------------"
|
||||||
|
|
||||||
|
# Wait a bit more for services to fully start
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
docker exec codeflash-unified supervisorctl status
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 6: Show API key
|
||||||
|
echo "=========================================="
|
||||||
|
echo " ✓ DEPLOYMENT COMPLETE!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
API_KEY=$(docker exec codeflash-unified cat /app/API_KEY.txt 2>/dev/null || echo "API key not yet generated")
|
||||||
|
|
||||||
|
if [ "$API_KEY" != "API key not yet generated" ]; then
|
||||||
|
echo "Your API Key: $API_KEY"
|
||||||
|
echo ""
|
||||||
|
echo "To use the CLI, run these commands:"
|
||||||
|
echo ""
|
||||||
|
echo " cd /Users/saga4/orgs/optimize-me"
|
||||||
|
echo " export CODEFLASH_API_KEY=$API_KEY"
|
||||||
|
echo " export CODEFLASH_AIS_SERVER=local"
|
||||||
|
echo " export CODEFLASH_CFAPI_SERVER=local"
|
||||||
|
echo " codeflash --file src/math/computation.py --function gcd_recursive --no-pr -v"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "Services are still initializing. View logs with:"
|
||||||
|
echo " docker logs -f codeflash-unified"
|
||||||
|
echo ""
|
||||||
|
echo "Once you see 'CODEFLASH SETUP COMPLETE!', retrieve your API key with:"
|
||||||
|
echo " docker exec codeflash-unified cat /app/API_KEY.txt"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
echo "Useful commands:"
|
||||||
|
echo " View logs: docker logs -f codeflash-unified"
|
||||||
|
echo " Restart: docker restart codeflash-unified"
|
||||||
|
echo " Stop: docker stop codeflash-unified"
|
||||||
|
echo " Check services: docker exec codeflash-unified supervisorctl status"
|
||||||
|
echo ""
|
||||||
138
deployment/onprem-simple/init-db.sh
Normal file
138
deployment/onprem-simple/init-db.sh
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "==================================="
|
||||||
|
echo "Initializing Codeflash Database"
|
||||||
|
echo "==================================="
|
||||||
|
|
||||||
|
# Wait for PostgreSQL to be ready
|
||||||
|
echo "Waiting for PostgreSQL to start..."
|
||||||
|
timeout=60
|
||||||
|
counter=0
|
||||||
|
until pg_isready -h localhost -p 5432 -U codeflash 2>/dev/null; do
|
||||||
|
counter=$((counter + 1))
|
||||||
|
if [ $counter -gt $timeout ]; then
|
||||||
|
echo "ERROR: PostgreSQL did not start within ${timeout} seconds"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "PostgreSQL is ready!"
|
||||||
|
|
||||||
|
# Run Prisma migrations
|
||||||
|
echo ""
|
||||||
|
echo "Running Prisma migrations..."
|
||||||
|
cd /common
|
||||||
|
export DATABASE_URL="${DATABASE_URL:-postgresql://codeflash:codeflash@localhost:5432/codeflash}"
|
||||||
|
npx prisma migrate deploy
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Checking for existing users..."
|
||||||
|
USER_COUNT=$(psql "$DATABASE_URL" -t -c "SELECT COUNT(*) FROM users;" 2>/dev/null || echo "0")
|
||||||
|
USER_COUNT=$(echo $USER_COUNT | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$USER_COUNT" = "0" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "No users found. Creating default user and API key..."
|
||||||
|
|
||||||
|
# Hardcoded API key for on-premise deployment
|
||||||
|
# Unhashed key (what users will use): cf-LDKLmsqjcZeX6SvjFPTz66NWgTV25njdWNUxinokmJcfegwRWytqFoJBoCkAKQad
|
||||||
|
# This is the SHA-384 hash stored in the database:
|
||||||
|
API_KEY_UNHASHED="LDKLmsqjcZeX6SvjFPTz66NWgTV25njdWNUxinokmJcfegwRWytqFoJBoCkAKQad"
|
||||||
|
API_KEY_HASHED="uXkhQcmQVmZbOpMtPMUTfeLRZOD3-s6GzYV1IpLMtJeHX4I9P8Ej_Kx3RftkP9yw"
|
||||||
|
SUFFIX="KQad"
|
||||||
|
|
||||||
|
# Use environment variables or defaults for user information
|
||||||
|
DEFAULT_USER_ID="${DEFAULT_USER_ID:-github|10488227}"
|
||||||
|
DEFAULT_USERNAME="${DEFAULT_USERNAME:-Saga4}"
|
||||||
|
DEFAULT_EMAIL="${DEFAULT_EMAIL:-sarthak.agarwal.cse12@iitbhu.ac.in}"
|
||||||
|
DEFAULT_NAME="${DEFAULT_NAME:-$DEFAULT_USERNAME}"
|
||||||
|
|
||||||
|
echo "Creating user: $DEFAULT_USERNAME (ID: $DEFAULT_USER_ID)"
|
||||||
|
|
||||||
|
# Insert user
|
||||||
|
psql "$DATABASE_URL" <<-EOSQL
|
||||||
|
INSERT INTO users (user_id, github_username, email, name, onboarding_completed, created_at)
|
||||||
|
VALUES ('$DEFAULT_USER_ID', '$DEFAULT_USERNAME', '$DEFAULT_EMAIL', '$DEFAULT_NAME', true, NOW())
|
||||||
|
ON CONFLICT (user_id) DO NOTHING;
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
# Insert API key (HASHED version in database)
|
||||||
|
psql "$DATABASE_URL" <<-EOSQL
|
||||||
|
INSERT INTO cf_api_keys (key, suffix, name, user_id, tier, created_at)
|
||||||
|
VALUES ('$API_KEY_HASHED', '$SUFFIX', 'Default API Key', '$DEFAULT_USER_ID', 'free', NOW());
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
# Insert subscription with unlimited usage for on-premise deployments
|
||||||
|
echo "Creating unlimited subscription for on-premise deployment..."
|
||||||
|
psql "$DATABASE_URL" <<-EOSQL
|
||||||
|
INSERT INTO subscriptions (
|
||||||
|
id,
|
||||||
|
user_id,
|
||||||
|
stripe_customer_id,
|
||||||
|
stripe_subscription_id,
|
||||||
|
plan_type,
|
||||||
|
optimizations_used,
|
||||||
|
optimizations_limit,
|
||||||
|
subscription_status,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
gen_random_uuid(),
|
||||||
|
'$DEFAULT_USER_ID',
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
'enterprise',
|
||||||
|
0,
|
||||||
|
999999999,
|
||||||
|
'active',
|
||||||
|
NOW(),
|
||||||
|
NOW()
|
||||||
|
)
|
||||||
|
ON CONFLICT (user_id) DO NOTHING;
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
# Format API key with cf- prefix for display (UNHASHED version for users)
|
||||||
|
DISPLAY_API_KEY="cf-${API_KEY_UNHASHED}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "======================================"
|
||||||
|
echo " CODEFLASH SETUP COMPLETE!"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
echo "User: $DEFAULT_USERNAME"
|
||||||
|
echo "Email: $DEFAULT_EMAIL"
|
||||||
|
echo ""
|
||||||
|
echo "Your API Key: $DISPLAY_API_KEY"
|
||||||
|
echo ""
|
||||||
|
echo "Save this API key! You'll need it to configure the Codeflash CLI."
|
||||||
|
echo ""
|
||||||
|
echo "To use the CLI, set these environment variables:"
|
||||||
|
echo " export CODEFLASH_API_KEY=$DISPLAY_API_KEY"
|
||||||
|
echo " export CODEFLASH_AIS_SERVER=local"
|
||||||
|
echo " export CODEFLASH_CFAPI_SERVER=local"
|
||||||
|
echo ""
|
||||||
|
echo "Or create a .env file in your project:"
|
||||||
|
echo " CODEFLASH_API_KEY=$DISPLAY_API_KEY"
|
||||||
|
echo " CODEFLASH_AIS_SERVER=local"
|
||||||
|
echo " CODEFLASH_CFAPI_SERVER=local"
|
||||||
|
echo ""
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Save API key to file for easy retrieval
|
||||||
|
echo "$DISPLAY_API_KEY" > /app/API_KEY.txt
|
||||||
|
echo "API key also saved to: /app/API_KEY.txt"
|
||||||
|
echo "(Retrieve anytime with: docker exec <container> cat /app/API_KEY.txt)"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
echo "Found $USER_COUNT existing user(s). Skipping user creation."
|
||||||
|
echo ""
|
||||||
|
echo "To retrieve an existing API key, run:"
|
||||||
|
echo " docker exec <container-name> psql \$DATABASE_URL -c \"SELECT key FROM cf_api_keys LIMIT 1;\""
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Database initialization complete!"
|
||||||
90
deployment/onprem-simple/startup.sh
Normal file
90
deployment/onprem-simple/startup.sh
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "==============================="
|
||||||
|
echo "Starting Codeflash Services"
|
||||||
|
echo "==============================="
|
||||||
|
|
||||||
|
# Initialize PostgreSQL if needed
|
||||||
|
if [ ! -f "/var/lib/postgresql/data/PG_VERSION" ]; then
|
||||||
|
echo "Initializing PostgreSQL database..."
|
||||||
|
su - postgres -c "initdb -D /var/lib/postgresql/data"
|
||||||
|
|
||||||
|
# Configure PostgreSQL
|
||||||
|
echo "Configuring PostgreSQL..."
|
||||||
|
cat >> /var/lib/postgresql/data/postgresql.conf <<EOF
|
||||||
|
listen_addresses = '*'
|
||||||
|
port = 5432
|
||||||
|
max_connections = 100
|
||||||
|
shared_buffers = 128MB
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >> /var/lib/postgresql/data/pg_hba.conf <<EOF
|
||||||
|
host all all 0.0.0.0/0 md5
|
||||||
|
host all all ::0/0 md5
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start PostgreSQL temporarily to ensure user and database exist
|
||||||
|
echo "Starting PostgreSQL for setup..."
|
||||||
|
su - postgres -c "pg_ctl -D /var/lib/postgresql/data start -o '-c logging_collector=off'"
|
||||||
|
|
||||||
|
# Wait for PostgreSQL to be ready
|
||||||
|
echo "Waiting for PostgreSQL to be ready..."
|
||||||
|
for i in {1..30}; do
|
||||||
|
if su - postgres -c "pg_isready" > /dev/null 2>&1; then
|
||||||
|
echo "PostgreSQL is ready!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if codeflash user exists, create if not
|
||||||
|
USER_EXISTS=$(su - postgres -c "psql -tAc \"SELECT 1 FROM pg_roles WHERE rolname='codeflash'\"" 2>/dev/null || echo "0")
|
||||||
|
if [ "$USER_EXISTS" != "1" ]; then
|
||||||
|
echo "Creating database user and database..."
|
||||||
|
su - postgres -c "psql -c \"CREATE USER codeflash WITH PASSWORD 'codeflash';\""
|
||||||
|
su - postgres -c "psql -c \"CREATE DATABASE codeflash OWNER codeflash;\""
|
||||||
|
su - postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE codeflash TO codeflash;\""
|
||||||
|
echo "User and database created successfully!"
|
||||||
|
else
|
||||||
|
echo "Database user already exists, skipping creation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop PostgreSQL so supervisord can start it properly
|
||||||
|
echo "Stopping temporary PostgreSQL instance..."
|
||||||
|
su - postgres -c "pg_ctl -D /var/lib/postgresql/data stop -w"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Set default DATABASE_URL if not provided
|
||||||
|
export DATABASE_URL="${DATABASE_URL:-postgresql://codeflash:codeflash@localhost:5432/codeflash}"
|
||||||
|
|
||||||
|
# Auto-generate SECRET_KEY if not provided
|
||||||
|
if [ -z "$SECRET_KEY" ]; then
|
||||||
|
echo "⚠️ SECRET_KEY not provided, generating random key..."
|
||||||
|
export SECRET_KEY=$(openssl rand -hex 32)
|
||||||
|
echo "✓ Generated SECRET_KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set default URLs if not provided
|
||||||
|
export NEXT_PUBLIC_APP_URL="${NEXT_PUBLIC_APP_URL:-http://localhost:3000}"
|
||||||
|
export WEBAPP_URL="${WEBAPP_URL:-http://localhost:3000}"
|
||||||
|
export CODEFLASH_CFAPI_URL="${CODEFLASH_CFAPI_URL:-http://localhost:3001}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Starting services with supervisord..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Start supervisord in background
|
||||||
|
/usr/bin/supervisord -c /etc/supervisord.conf &
|
||||||
|
SUPERVISOR_PID=$!
|
||||||
|
|
||||||
|
# Wait for PostgreSQL to be ready under supervisord
|
||||||
|
echo "Waiting for PostgreSQL to start under supervisord..."
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Run database initialization (migrations and API key creation)
|
||||||
|
/app/init-db.sh
|
||||||
|
|
||||||
|
# Keep supervisord running
|
||||||
|
wait $SUPERVISOR_PID
|
||||||
62
deployment/onprem-simple/supervisord.conf
Normal file
62
deployment/onprem-simple/supervisord.conf
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/var/log/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[supervisorctl]
|
||||||
|
serverurl=unix:///var/run/supervisor.sock
|
||||||
|
|
||||||
|
[unix_http_server]
|
||||||
|
file=/var/run/supervisor.sock
|
||||||
|
chmod=0700
|
||||||
|
|
||||||
|
[rpcinterface:supervisor]
|
||||||
|
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||||
|
|
||||||
|
[program:postgres]
|
||||||
|
command=/usr/libexec/postgresql15/postgres -D /var/lib/postgresql/data
|
||||||
|
user=postgres
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=1
|
||||||
|
|
||||||
|
[program:aiservice]
|
||||||
|
command=/bin/sh -c "cd /app/aiservice && uv run gunicorn -c gunicorn.conf.py aiservice.asgi:application --bind 0.0.0.0:8000 --timeout 600 --workers 2"
|
||||||
|
directory=/app/aiservice
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=10
|
||||||
|
environment=PYTHONUNBUFFERED="1",DATABASE_URL="postgresql://codeflash:codeflash@localhost:5432/codeflash"
|
||||||
|
|
||||||
|
[program:cf-api]
|
||||||
|
command=/bin/sh -c "cd /app/cf-api && npm start"
|
||||||
|
directory=/app/cf-api
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=10
|
||||||
|
environment=NODE_ENV="local",DATABASE_URL="postgresql://codeflash:codeflash@localhost:5432/codeflash"
|
||||||
|
|
||||||
|
[program:cf-webapp]
|
||||||
|
command=/bin/sh -c "cd /app/cf-webapp && npm start"
|
||||||
|
directory=/app/cf-webapp
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=10
|
||||||
|
environment=DATABASE_URL="postgresql://codeflash:codeflash@localhost:5432/codeflash",NODE_ENV="production"
|
||||||
81
django/.dockerignore
Normal file
81
django/.dockerignore
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Python virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
aiservice/.venv/
|
||||||
|
aiservice/venv/
|
||||||
|
aiservice/__pycache__/
|
||||||
|
|
||||||
|
# Python cache files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# IDEs
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
.tmp/
|
||||||
|
|
@ -3,15 +3,15 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Literal
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from openai import AsyncOpenAI
|
from openai import AsyncOpenAI
|
||||||
from openai.lib.azure import AsyncAzureOpenAI
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
|
|
||||||
|
|
||||||
IS_PRODUCTION = os.environ.get("ENVIRONMENT", default="") == "PRODUCTION"
|
IS_PRODUCTION = os.environ.get("ENVIRONMENT", default="") == "PRODUCTION"
|
||||||
|
|
||||||
LOGGING_FORMAT = "[%(levelname)s] %(message)s"
|
LOGGING_FORMAT = "[%(levelname)s] %(message)s"
|
||||||
|
|
@ -41,31 +41,34 @@ def debug_log_sensitive_data_from_callable(message: Callable[[], str | None]) ->
|
||||||
logging.debug(message())
|
logging.debug(message())
|
||||||
|
|
||||||
|
|
||||||
def create_openai_client_instance(
|
def create_llm_client(model_type: Literal["openai", "anthropic", "google"]) -> AsyncOpenAI | None:
|
||||||
client_type: str = os.environ.get("OPENAI_API_TYPE", default="azure"),
|
# use azure or openai
|
||||||
) -> AsyncOpenAI | AsyncAzureOpenAI:
|
openai_api_type = os.environ.get("OPENAI_API_TYPE")
|
||||||
if client_type == "azure":
|
openai_api_base_url = os.environ.get(
|
||||||
logging.info("OpenAIClient: Using Azure OpenAI service.")
|
"OPENAI_API_BASE"
|
||||||
openai_client: AsyncOpenAI | AsyncAzureOpenAI = AsyncAzureOpenAI(
|
) # for us it is https://codeflash-openai-service-eastus2-0.openai.azure.com/openai/v1/
|
||||||
# https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning
|
# we need both of the above to run on azure
|
||||||
api_version="2024-08-01-preview",
|
azure_api_key, openai_key, anthropic_key, google_key = (
|
||||||
# https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
|
os.environ.get("AZURE_OPENAI_API_KEY"),
|
||||||
azure_endpoint="https://codeflash-openai-service-eastus2-0.openai.azure.com",
|
os.environ.get("OPENAI_API_KEY"),
|
||||||
|
os.environ.get("ANTHROPIC_API_KEY"),
|
||||||
)
|
os.environ.get("GEMINI_API_KEY"),
|
||||||
else:
|
|
||||||
logging.info("OpenAIClient: Using OpenAI API.")
|
|
||||||
openai_client = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
|
||||||
return openai_client
|
|
||||||
|
|
||||||
|
|
||||||
def create_claude_client() -> AsyncOpenAI:
|
|
||||||
logging.info("Claude Client")
|
|
||||||
claude_client: AsyncOpenAI = AsyncOpenAI(
|
|
||||||
api_key=os.environ.get("ANTHROPIC_API_KEY"),
|
|
||||||
base_url="https://api.anthropic.com/v1/",
|
|
||||||
)
|
)
|
||||||
return claude_client
|
if model_type == "openai" and azure_api_key and openai_api_type == "azure" and openai_api_base_url:
|
||||||
|
# check for azure first
|
||||||
|
return AsyncOpenAI(api_key=azure_api_key, base_url=openai_api_base_url)
|
||||||
|
if model_type == "openai" and openai_key:
|
||||||
|
return AsyncOpenAI(api_key=openai_key) # baseurl not needed for regular openai
|
||||||
|
if model_type == "anthropic" and anthropic_key:
|
||||||
|
return AsyncOpenAI(api_key=anthropic_key, base_url="https://api.anthropic.com/v1/")
|
||||||
|
# # for future use : gemini supported only via GEMINI_API_KEY at the moment, todo for vertex ai
|
||||||
|
if model_type == "google" and google_key:
|
||||||
|
return AsyncOpenAI(api_key=google_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
openai_client = create_openai_client_instance()
|
llm_clients = {
|
||||||
|
"openai": create_llm_client("openai"),
|
||||||
|
"anthropic": create_llm_client("anthropic"),
|
||||||
|
# "google": create_llm_client("google"), # no need to instantiate right now as we're not using it
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import os
|
import os
|
||||||
from typing import Any
|
from typing import Any, Literal
|
||||||
|
|
||||||
from pydantic.dataclasses import dataclass
|
from pydantic.dataclasses import dataclass
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ from pydantic.dataclasses import dataclass
|
||||||
class LLM:
|
class LLM:
|
||||||
name: str # On Azure OpenAI Service, this is the deployment name
|
name: str # On Azure OpenAI Service, this is the deployment name
|
||||||
max_tokens: int
|
max_tokens: int
|
||||||
api_version: str = ""
|
model_type: Literal["openai", "anthropic", "google"]
|
||||||
# Add new pricing attributes in USD per 1M tokens
|
# Add new pricing attributes in USD per 1M tokens
|
||||||
input_cost: float | None = None
|
input_cost: float | None = None
|
||||||
output_cost: float | None = None
|
output_cost: float | None = None
|
||||||
|
|
@ -24,6 +24,7 @@ class LLM:
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_4_OMNI(LLM):
|
class GPT_4_OMNI(LLM):
|
||||||
name: str = "gpt-4o-2" if os.environ.get("OPENAI_API_TYPE") == "azure" else "gpt-4o"
|
name: str = "gpt-4o-2" if os.environ.get("OPENAI_API_TYPE") == "azure" else "gpt-4o"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 128000
|
max_tokens: int = 128000
|
||||||
input_cost: float = 2.50
|
input_cost: float = 2.50
|
||||||
output_cost: float = 10.00
|
output_cost: float = 10.00
|
||||||
|
|
@ -32,6 +33,7 @@ class GPT_4_OMNI(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_4_128k(LLM):
|
class GPT_4_128k(LLM):
|
||||||
name: str = "gpt-4-1106-preview"
|
name: str = "gpt-4-1106-preview"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 128000
|
max_tokens: int = 128000
|
||||||
input_cost: float = 10.00
|
input_cost: float = 10.00
|
||||||
output_cost: float = 30.00
|
output_cost: float = 30.00
|
||||||
|
|
@ -40,6 +42,7 @@ class GPT_4_128k(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_4_32k(LLM):
|
class GPT_4_32k(LLM):
|
||||||
name: str = "gpt4-32k"
|
name: str = "gpt4-32k"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 32768
|
max_tokens: int = 32768
|
||||||
input_cost: float = 60.00
|
input_cost: float = 60.00
|
||||||
output_cost: float = 120.00
|
output_cost: float = 120.00
|
||||||
|
|
@ -48,6 +51,7 @@ class GPT_4_32k(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_4(LLM):
|
class GPT_4(LLM):
|
||||||
name: str = "gpt-4-0613"
|
name: str = "gpt-4-0613"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 8192
|
max_tokens: int = 8192
|
||||||
input_cost: float = 30.00
|
input_cost: float = 30.00
|
||||||
output_cost: float = 60.00
|
output_cost: float = 60.00
|
||||||
|
|
@ -56,6 +60,7 @@ class GPT_4(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_3_5_Turbo_16k(LLM):
|
class GPT_3_5_Turbo_16k(LLM):
|
||||||
name: str = "gpt-3.5-turbo-16k"
|
name: str = "gpt-3.5-turbo-16k"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 16384
|
max_tokens: int = 16384
|
||||||
input_cost: float = 3.00
|
input_cost: float = 3.00
|
||||||
output_cost: float = 4.00
|
output_cost: float = 4.00
|
||||||
|
|
@ -64,6 +69,7 @@ class GPT_3_5_Turbo_16k(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_3_5_Turbo(LLM):
|
class GPT_3_5_Turbo(LLM):
|
||||||
name: str = "gpt-3.5-turbo"
|
name: str = "gpt-3.5-turbo"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 4096
|
max_tokens: int = 4096
|
||||||
input_cost: float = 0.50
|
input_cost: float = 0.50
|
||||||
output_cost: float = 1.50
|
output_cost: float = 1.50
|
||||||
|
|
@ -72,6 +78,7 @@ class GPT_3_5_Turbo(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class Antropic_Claude_3_7(LLM):
|
class Antropic_Claude_3_7(LLM):
|
||||||
name: str = "claude-3-7-sonnet-20250219"
|
name: str = "claude-3-7-sonnet-20250219"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
input_cost: float = 3.00
|
input_cost: float = 3.00
|
||||||
output_cost: float = 15.00
|
output_cost: float = 15.00
|
||||||
|
|
@ -80,8 +87,8 @@ class Antropic_Claude_3_7(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class Anthropic_Claude_4(LLM):
|
class Anthropic_Claude_4(LLM):
|
||||||
name: str = "claude-sonnet-4-20250514"
|
name: str = "claude-sonnet-4-20250514"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "anthropic"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
api_version: str = ""
|
|
||||||
input_cost: float = 3.00
|
input_cost: float = 3.00
|
||||||
output_cost: float = 15.00
|
output_cost: float = 15.00
|
||||||
|
|
||||||
|
|
@ -90,8 +97,8 @@ class Anthropic_Claude_4(LLM):
|
||||||
class OpenAI_GPT_4_1(LLM):
|
class OpenAI_GPT_4_1(LLM):
|
||||||
# name: str = "azure/gpt-4.1"
|
# name: str = "azure/gpt-4.1"
|
||||||
name: str = "gpt-4.1"
|
name: str = "gpt-4.1"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
api_version: str = "2024-12-01-preview"
|
|
||||||
input_cost: float = 2.00
|
input_cost: float = 2.00
|
||||||
output_cost: float = 8.00
|
output_cost: float = 8.00
|
||||||
|
|
||||||
|
|
@ -99,14 +106,15 @@ class OpenAI_GPT_4_1(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class Gemini_2_5(LLM):
|
class Gemini_2_5(LLM):
|
||||||
name: str = "gemini/gemini-2.5-pro-preview-03-25"
|
name: str = "gemini/gemini-2.5-pro-preview-03-25"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "google"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class OpenAI_GPT_O_3(LLM):
|
class OpenAI_GPT_O_3(LLM):
|
||||||
name: str = "azure/o3"
|
name: str = "azure/o3"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
api_version = "2025-01-01-preview"
|
|
||||||
input_cost: float = 2.00
|
input_cost: float = 2.00
|
||||||
output_cost: float = 8.00
|
output_cost: float = 8.00
|
||||||
|
|
||||||
|
|
@ -114,15 +122,16 @@ class OpenAI_GPT_O_3(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class OpenAI_GPT_O_4_MINI(LLM):
|
class OpenAI_GPT_O_4_MINI(LLM):
|
||||||
name: str = "azure/o4-mini"
|
name: str = "azure/o4-mini"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
api_version = "2024-12-01-preview"
|
|
||||||
input_cost: float = 1.10
|
input_cost: float = 1.10
|
||||||
output_cost: float = 4.40
|
output_cost: float = 4.40
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_5(LLM):
|
class GPT_5(LLM): # IT IS TOO SLOW AT THE MOMENT, just here for documentation
|
||||||
name: str = "gpt-5"
|
name: str = "gpt-5-codex"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
input_cost: float = 1.25
|
input_cost: float = 1.25
|
||||||
output_cost: float = 10.00
|
output_cost: float = 10.00
|
||||||
|
|
@ -131,6 +140,7 @@ class GPT_5(LLM):
|
||||||
@dataclass
|
@dataclass
|
||||||
class GPT_4_1_Nano(LLM):
|
class GPT_4_1_Nano(LLM):
|
||||||
name: str = "gpt-4.1-nano"
|
name: str = "gpt-4.1-nano"
|
||||||
|
model_type: Literal["openai", "anthropic", "google"] = "openai"
|
||||||
max_tokens: int = 100000
|
max_tokens: int = 100000
|
||||||
input_cost: float = 0.10
|
input_cost: float = 0.10
|
||||||
output_cost: float = 0.40
|
output_cost: float = 0.40
|
||||||
|
|
@ -148,8 +158,12 @@ def calculate_llm_cost(response: Any, llm: LLM) -> float | None:
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
usage = response.usage
|
usage = response.usage
|
||||||
prompt_tokens = usage.prompt_tokens
|
if hasattr(usage, "prompt_tokens"): # for openai
|
||||||
completion_tokens = usage.completion_tokens
|
prompt_tokens = usage.prompt_tokens
|
||||||
|
completion_tokens = usage.completion_tokens
|
||||||
|
else: # for claude
|
||||||
|
prompt_tokens = usage.input_tokens
|
||||||
|
completion_tokens = usage.output_tokens
|
||||||
|
|
||||||
prompt_cost = (prompt_tokens / 1_000_000) * llm.input_cost
|
prompt_cost = (prompt_tokens / 1_000_000) * llm.input_cost
|
||||||
completion_cost = (completion_tokens / 1_000_000) * llm.output_cost
|
completion_cost = (completion_tokens / 1_000_000) * llm.output_cost
|
||||||
|
|
@ -163,11 +177,45 @@ def calculate_llm_cost(response: Any, llm: LLM) -> float | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
EXPLAIN_MODEL: LLM = OpenAI_GPT_4_1()
|
def _get_openai_model() -> LLM:
|
||||||
PLAN_MODEL: LLM = OpenAI_GPT_4_1()
|
"""Return OpenAI GPT-4.1 if available, otherwise falls back to Anthropic Claude 4.
|
||||||
EXECUTE_MODEL: LLM = OpenAI_GPT_4_1()
|
|
||||||
OPTIMIZE_MODEL: LLM = OpenAI_GPT_4_1()
|
Returns:
|
||||||
REFINEMENT_MODEL: LLM = Anthropic_Claude_4()
|
LLM: The appropriate model instance based on available API keys.
|
||||||
EXPLANATIONS_MODEL: LLM = Anthropic_Claude_4()
|
|
||||||
RANKING_MODEL: LLM = OpenAI_GPT_4_1()
|
"""
|
||||||
OPTIMIZATION_REVIEW_MODEL: LLM = Anthropic_Claude_4()
|
if os.environ.get("AZURE_OPENAI_API_KEY") or os.environ.get("OPENAI_API_KEY"):
|
||||||
|
return OpenAI_GPT_4_1()
|
||||||
|
# Fall back to Anthropic if OpenAI not available
|
||||||
|
if os.environ.get("ANTHROPIC_API_KEY"):
|
||||||
|
return Anthropic_Claude_4()
|
||||||
|
# Default to OpenAI (will fail gracefully with clear error from env_specific.py)
|
||||||
|
return OpenAI_GPT_4_1()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_anthropic_model() -> LLM:
|
||||||
|
"""Returns Anthropic Claude 4 if available, otherwise falls back to OpenAI GPT-4.1.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
LLM: The appropriate model instance based on available API keys.
|
||||||
|
|
||||||
|
""" # noqa: D401
|
||||||
|
if os.environ.get("ANTHROPIC_API_KEY"):
|
||||||
|
return Anthropic_Claude_4()
|
||||||
|
# Fall back to OpenAI if Anthropic not available
|
||||||
|
if os.environ.get("AZURE_OPENAI_API_KEY") or os.environ.get("OPENAI_API_KEY"):
|
||||||
|
return OpenAI_GPT_4_1()
|
||||||
|
# Default to Claude (will fail gracefully with clear error from env_specific.py)
|
||||||
|
return Anthropic_Claude_4()
|
||||||
|
|
||||||
|
|
||||||
|
# Dynamically select models based on available API keys
|
||||||
|
EXPLAIN_MODEL: LLM = _get_openai_model()
|
||||||
|
PLAN_MODEL: LLM = _get_openai_model()
|
||||||
|
EXECUTE_MODEL: LLM = _get_openai_model()
|
||||||
|
OPTIMIZE_MODEL: LLM = _get_openai_model()
|
||||||
|
RANKING_MODEL: LLM = _get_openai_model()
|
||||||
|
|
||||||
|
REFINEMENT_MODEL: LLM = _get_anthropic_model()
|
||||||
|
EXPLANATIONS_MODEL: LLM = _get_anthropic_model()
|
||||||
|
OPTIMIZATION_REVIEW_MODEL: LLM = _get_anthropic_model()
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from aiservice.analytics.posthog import ph
|
from aiservice.analytics.posthog import ph
|
||||||
from aiservice.common_utils import validate_trace_id
|
from aiservice.common_utils import validate_trace_id
|
||||||
from aiservice.env_specific import create_claude_client, debug_log_sensitive_data
|
from aiservice.env_specific import create_llm_client, debug_log_sensitive_data, llm_clients
|
||||||
from aiservice.models.aimodels import EXPLANATIONS_MODEL, LLM, calculate_llm_cost
|
from aiservice.models.aimodels import EXPLANATIONS_MODEL, LLM, calculate_llm_cost
|
||||||
from log_features.log_event import update_optimization_cost
|
from log_features.log_event import update_optimization_cost
|
||||||
from log_features.log_features import log_features
|
from log_features.log_features import log_features
|
||||||
|
|
@ -213,16 +213,16 @@ async def explain_optimizations( # noqa: D417
|
||||||
| ChatCompletionToolMessageParam
|
| ChatCompletionToolMessageParam
|
||||||
| ChatCompletionFunctionMessageParam
|
| ChatCompletionFunctionMessageParam
|
||||||
] = [system_message, user_message]
|
] = [system_message, user_message]
|
||||||
async with create_claude_client() as claude_client:
|
llm_client = llm_clients[explanations_model.model_type]
|
||||||
try:
|
try:
|
||||||
output = await claude_client.with_options(max_retries=2).chat.completions.create(
|
output = await llm_client.with_options(max_retries=2).chat.completions.create(
|
||||||
model=explanations_model.name, messages=messages, n=1
|
model=explanations_model.name, messages=messages, n=1
|
||||||
)
|
)
|
||||||
await update_optimization_cost(trace_id=data.trace_id, cost=calculate_llm_cost(output, explanations_model))
|
await update_optimization_cost(trace_id=data.trace_id, cost=calculate_llm_cost(output, explanations_model))
|
||||||
except OpenAIError as e:
|
except OpenAIError as e:
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
debug_log_sensitive_data(f"Failed to generate new explanation, Error message: {e}")
|
debug_log_sensitive_data(f"Failed to generate new explanation, Error message: {e}")
|
||||||
return ExplanationsErrorResponseSchema(error=str(e))
|
return ExplanationsErrorResponseSchema(error=str(e))
|
||||||
debug_log_sensitive_data(f"AIClient optimization response:\n{output}")
|
debug_log_sensitive_data(f"AIClient optimization response:\n{output}")
|
||||||
if output.usage is not None:
|
if output.usage is not None:
|
||||||
ph(
|
ph(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from enum import Enum
|
||||||
from typing import TYPE_CHECKING, cast
|
from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from aiservice.env_specific import create_claude_client, debug_log_sensitive_data
|
from aiservice.env_specific import create_llm_client, debug_log_sensitive_data, llm_clients
|
||||||
from aiservice.models.aimodels import OPTIMIZATION_REVIEW_MODEL, calculate_llm_cost
|
from aiservice.models.aimodels import OPTIMIZATION_REVIEW_MODEL, calculate_llm_cost
|
||||||
from log_features.log_event import update_optimization_cost, update_optimization_features_review
|
from log_features.log_event import update_optimization_cost, update_optimization_features_review
|
||||||
from ninja import NinjaAPI, Schema
|
from ninja import NinjaAPI, Schema
|
||||||
|
|
@ -142,7 +142,9 @@ Output as a json markdown block with the key named as 'rating' and value being o
|
||||||
|
|
||||||
|
|
||||||
async def get_optimization_review(
|
async def get_optimization_review(
|
||||||
request, data: OptimizationReviewSchema, optimization_review_model: LLM = OPTIMIZATION_REVIEW_MODEL
|
request,
|
||||||
|
data: OptimizationReviewSchema,
|
||||||
|
optimization_review_model: LLM = OPTIMIZATION_REVIEW_MODEL, # noqa: ANN001
|
||||||
) -> tuple[int, OptimizationReviewResponseSchema | OptimizationReviewErrorSchema]:
|
) -> tuple[int, OptimizationReviewResponseSchema | OptimizationReviewErrorSchema]:
|
||||||
"""Compute optimization review via Claude."""
|
"""Compute optimization review via Claude."""
|
||||||
ph(request.user, "aiservice-optimization-review-called")
|
ph(request.user, "aiservice-optimization-review-called")
|
||||||
|
|
@ -151,11 +153,11 @@ async def get_optimization_review(
|
||||||
|
|
||||||
debug_log_sensitive_data(f"{messages[0]}{messages[1]}")
|
debug_log_sensitive_data(f"{messages[0]}{messages[1]}")
|
||||||
|
|
||||||
async with create_claude_client() as claude_client:
|
llm_client = llm_clients[optimization_review_model.model_type]
|
||||||
# Call Claude API with retries
|
# Call Claude API with retries
|
||||||
response = await claude_client.with_options(max_retries=2).chat.completions.create(
|
response = await llm_client.with_options(max_retries=2).chat.completions.create(
|
||||||
model=optimization_review_model.name, messages=messages
|
model=optimization_review_model.name, messages=messages
|
||||||
)
|
)
|
||||||
# Calculate and update cost
|
# Calculate and update cost
|
||||||
cost = calculate_llm_cost(response, optimization_review_model)
|
cost = calculate_llm_cost(response, optimization_review_model)
|
||||||
if cost:
|
if cost:
|
||||||
|
|
@ -197,7 +199,8 @@ async def get_optimization_review(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
async def optimization_review(
|
async def optimization_review(
|
||||||
request, data: OptimizationReviewSchema
|
request,
|
||||||
|
data: OptimizationReviewSchema, # noqa: ANN001
|
||||||
) -> tuple[int, OptimizationReviewResponseSchema | OptimizationReviewErrorSchema]:
|
) -> tuple[int, OptimizationReviewResponseSchema | OptimizationReviewErrorSchema]:
|
||||||
response_code, output = await get_optimization_review(request, data)
|
response_code, output = await get_optimization_review(request, data)
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,18 @@ from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import libcst as cst
|
import libcst as cst
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
from aiservice.analytics.posthog import ph
|
||||||
|
from aiservice.common_utils import parse_python_version, should_hack_for_demo, validate_trace_id
|
||||||
|
from aiservice.env_specific import debug_log_sensitive_data, debug_log_sensitive_data_from_callable, llm_clients
|
||||||
|
from aiservice.models.aimodels import OPTIMIZE_MODEL, calculate_llm_cost
|
||||||
|
from authapp.user import get_user_by_id
|
||||||
|
from log_features.log_event import log_optimization_event
|
||||||
|
from log_features.log_features import log_features
|
||||||
from ninja import NinjaAPI
|
from ninja import NinjaAPI
|
||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam
|
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from aiservice.analytics.posthog import ph
|
|
||||||
from aiservice.common_utils import parse_python_version, should_hack_for_demo, validate_trace_id
|
|
||||||
from aiservice.env_specific import debug_log_sensitive_data, debug_log_sensitive_data_from_callable, openai_client
|
|
||||||
from aiservice.models.aimodels import OPTIMIZE_MODEL, calculate_llm_cost
|
|
||||||
from authapp.user import get_user_by_id
|
|
||||||
from log_features.log_event import log_optimization_event
|
|
||||||
from log_features.log_features import log_features
|
|
||||||
from optimizer.context_utils.context_helpers import group_code
|
from optimizer.context_utils.context_helpers import group_code
|
||||||
from optimizer.context_utils.optimizer_context import (
|
from optimizer.context_utils.optimizer_context import (
|
||||||
BaseOptimizerContext,
|
BaseOptimizerContext,
|
||||||
|
|
@ -30,6 +30,7 @@ from optimizer.context_utils.optimizer_context import (
|
||||||
from optimizer.models import OptimizeSchema # noqa: TC001
|
from optimizer.models import OptimizeSchema # noqa: TC001
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from aiservice.models.aimodels import LLM
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from openai.types.chat import (
|
from openai.types.chat import (
|
||||||
ChatCompletionAssistantMessageParam,
|
ChatCompletionAssistantMessageParam,
|
||||||
|
|
@ -37,8 +38,6 @@ if TYPE_CHECKING:
|
||||||
ChatCompletionToolMessageParam,
|
ChatCompletionToolMessageParam,
|
||||||
)
|
)
|
||||||
|
|
||||||
from aiservice.models.aimodels import LLM
|
|
||||||
|
|
||||||
|
|
||||||
optimizations_json = [
|
optimizations_json = [
|
||||||
{
|
{
|
||||||
|
|
@ -138,8 +137,9 @@ async def optimize_python_code(
|
||||||
| ChatCompletionToolMessageParam
|
| ChatCompletionToolMessageParam
|
||||||
| ChatCompletionFunctionMessageParam
|
| ChatCompletionFunctionMessageParam
|
||||||
] = [system_message, user_message]
|
] = [system_message, user_message]
|
||||||
|
llm_client = llm_clients[optimize_model.model_type]
|
||||||
try:
|
try:
|
||||||
output = await openai_client.with_options(max_retries=3).chat.completions.create(
|
output = await llm_client.with_options(max_retries=3).chat.completions.create(
|
||||||
model=optimize_model.name, messages=messages, n=n
|
model=optimize_model.name, messages=messages, n=n
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -5,34 +5,30 @@ from pathlib import Path
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from ninja import NinjaAPI, Schema
|
|
||||||
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam
|
|
||||||
|
|
||||||
from aiservice.analytics.posthog import ph
|
from aiservice.analytics.posthog import ph
|
||||||
from aiservice.common_utils import parse_python_version, validate_trace_id
|
from aiservice.common_utils import parse_python_version, validate_trace_id
|
||||||
from aiservice.env_specific import (
|
from aiservice.env_specific import debug_log_sensitive_data, debug_log_sensitive_data_from_callable, llm_clients
|
||||||
debug_log_sensitive_data,
|
|
||||||
debug_log_sensitive_data_from_callable,
|
|
||||||
openai_client,
|
|
||||||
)
|
|
||||||
from aiservice.models.aimodels import OPTIMIZE_MODEL, calculate_llm_cost
|
from aiservice.models.aimodels import OPTIMIZE_MODEL, calculate_llm_cost
|
||||||
from log_features.log_event import update_optimization_cost
|
from log_features.log_event import update_optimization_cost
|
||||||
from log_features.log_features import log_features
|
from log_features.log_features import log_features
|
||||||
|
from ninja import NinjaAPI, Schema
|
||||||
|
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam
|
||||||
|
|
||||||
from optimizer.context_utils.optimizer_context import (
|
from optimizer.context_utils.optimizer_context import (
|
||||||
BaseOptimizerContext,
|
BaseOptimizerContext,
|
||||||
OptimizeErrorResponseSchema,
|
OptimizeErrorResponseSchema,
|
||||||
OptimizeResponseItemSchema,
|
|
||||||
OptimizeResponseSchema,
|
OptimizeResponseSchema,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from aiservice.models.aimodels import LLM
|
||||||
from openai.types.chat import (
|
from openai.types.chat import (
|
||||||
ChatCompletionAssistantMessageParam,
|
ChatCompletionAssistantMessageParam,
|
||||||
ChatCompletionFunctionMessageParam,
|
ChatCompletionFunctionMessageParam,
|
||||||
ChatCompletionToolMessageParam,
|
ChatCompletionToolMessageParam,
|
||||||
)
|
)
|
||||||
|
|
||||||
from aiservice.models.aimodels import LLM
|
from optimizer.context_utils.optimizer_context import OptimizeResponseItemSchema
|
||||||
|
|
||||||
|
|
||||||
optimize_line_profiler_api = NinjaAPI(urls_namespace="optimize-line-profiler")
|
optimize_line_profiler_api = NinjaAPI(urls_namespace="optimize-line-profiler")
|
||||||
|
|
@ -44,7 +40,7 @@ SYSTEM_PROMPT = (current_dir / "system_prompt.md").read_text()
|
||||||
USER_PROMPT = (current_dir / "user_prompt.md").read_text()
|
USER_PROMPT = (current_dir / "user_prompt.md").read_text()
|
||||||
|
|
||||||
|
|
||||||
async def optimize_python_code_line_profiler(
|
async def optimize_python_code_line_profiler( # noqa: D417
|
||||||
user_id: str,
|
user_id: str,
|
||||||
trace_id: str,
|
trace_id: str,
|
||||||
line_profiler_results: str,
|
line_profiler_results: str,
|
||||||
|
|
@ -52,7 +48,7 @@ async def optimize_python_code_line_profiler(
|
||||||
dependency_code: str | None = None,
|
dependency_code: str | None = None,
|
||||||
n: int = 1,
|
n: int = 1,
|
||||||
optimize_model: LLM = OPTIMIZE_MODEL,
|
optimize_model: LLM = OPTIMIZE_MODEL,
|
||||||
lsp_mode: bool = False,
|
lsp_mode: bool = False, # noqa: FBT001, FBT002
|
||||||
python_version: tuple[int, int, int] = (3, 12, 9),
|
python_version: tuple[int, int, int] = (3, 12, 9),
|
||||||
) -> list[OptimizeResponseItemSchema]:
|
) -> list[OptimizeResponseItemSchema]:
|
||||||
"""Optimize the given python code for performance using OpenAI's GPT-4o model.
|
"""Optimize the given python code for performance using OpenAI's GPT-4o model.
|
||||||
|
|
@ -92,8 +88,9 @@ async def optimize_python_code_line_profiler(
|
||||||
] = [system_message, user_message]
|
] = [system_message, user_message]
|
||||||
debug_log_sensitive_data(f"This was the user prompt\n {user_prompt}\n")
|
debug_log_sensitive_data(f"This was the user prompt\n {user_prompt}\n")
|
||||||
# TODO: Verify if the context window length is within the model capability
|
# TODO: Verify if the context window length is within the model capability
|
||||||
|
llm_client = llm_clients[optimize_model.model_type]
|
||||||
try:
|
try:
|
||||||
output = await openai_client.with_options(max_retries=3).chat.completions.create(
|
output = await llm_client.with_options(max_retries=3).chat.completions.create(
|
||||||
model=optimize_model.name, messages=messages, n=n
|
model=optimize_model.name, messages=messages, n=n
|
||||||
)
|
)
|
||||||
await update_optimization_cost(trace_id=trace_id, cost=calculate_llm_cost(output, optimize_model))
|
await update_optimization_cost(trace_id=trace_id, cost=calculate_llm_cost(output, optimize_model))
|
||||||
|
|
@ -140,12 +137,12 @@ class OptimizeSchemaLP(Schema):
|
||||||
@optimize_line_profiler_api.post(
|
@optimize_line_profiler_api.post(
|
||||||
"/", response={200: OptimizeResponseSchema, 400: OptimizeErrorResponseSchema, 500: OptimizeErrorResponseSchema}
|
"/", response={200: OptimizeResponseSchema, 400: OptimizeErrorResponseSchema, 500: OptimizeErrorResponseSchema}
|
||||||
)
|
)
|
||||||
async def optimize(request, data: OptimizeSchemaLP) -> tuple[int, OptimizeResponseSchema | OptimizeErrorResponseSchema]:
|
async def optimize(request, data: OptimizeSchemaLP) -> tuple[int, OptimizeResponseSchema | OptimizeErrorResponseSchema]: # noqa: ANN001
|
||||||
ph(request.user, "aiservice-optimize-called")
|
ph(request.user, "aiservice-optimize-called")
|
||||||
ctx: BaseOptimizerContext = BaseOptimizerContext.get_dynamic_context(SYSTEM_PROMPT, USER_PROMPT, data.source_code)
|
ctx: BaseOptimizerContext = BaseOptimizerContext.get_dynamic_context(SYSTEM_PROMPT, USER_PROMPT, data.source_code)
|
||||||
try:
|
try:
|
||||||
python_version: tuple[int, int, int] = parse_python_version(data.python_version)
|
python_version: tuple[int, int, int] = parse_python_version(data.python_version)
|
||||||
except:
|
except: # noqa: E722
|
||||||
return 400, OptimizeErrorResponseSchema(
|
return 400, OptimizeErrorResponseSchema(
|
||||||
error="Invalid Python version, it should look like 3.x.x. We only support Python 3.9 and above."
|
error="Invalid Python version, it should look like 3.x.x. We only support Python 3.9 and above."
|
||||||
)
|
)
|
||||||
|
|
@ -197,7 +194,7 @@ async def optimize(request, data: OptimizeSchemaLP) -> tuple[int, OptimizeRespon
|
||||||
|
|
||||||
response = OptimizeResponseSchema(optimizations=optimization_response_items)
|
response = OptimizeResponseSchema(optimizations=optimization_response_items)
|
||||||
|
|
||||||
def log_response():
|
def log_response() -> None:
|
||||||
debug_log_sensitive_data(f"Response:\n{response.json()}")
|
debug_log_sensitive_data(f"Response:\n{response.json()}")
|
||||||
for opt in response.optimizations:
|
for opt in response.optimizations:
|
||||||
debug_log_sensitive_data(f"Optimized source:\n{opt.source_code}")
|
debug_log_sensitive_data(f"Optimized source:\n{opt.source_code}")
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import libcst as cst
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from aiservice.analytics.posthog import ph
|
from aiservice.analytics.posthog import ph
|
||||||
from aiservice.common_utils import validate_trace_id
|
from aiservice.common_utils import validate_trace_id
|
||||||
from aiservice.env_specific import create_claude_client, debug_log_sensitive_data
|
from aiservice.env_specific import create_llm_client, debug_log_sensitive_data, llm_clients
|
||||||
from aiservice.models.aimodels import REFINEMENT_MODEL, calculate_llm_cost
|
from aiservice.models.aimodels import REFINEMENT_MODEL, calculate_llm_cost
|
||||||
from log_features.log_event import update_optimization_cost
|
from log_features.log_event import update_optimization_cost
|
||||||
from log_features.log_features import log_features
|
from log_features.log_features import log_features
|
||||||
|
|
@ -227,17 +227,17 @@ async def refinement( # noqa: D417
|
||||||
| ChatCompletionFunctionMessageParam
|
| ChatCompletionFunctionMessageParam
|
||||||
] = [system_message, user_message]
|
] = [system_message, user_message]
|
||||||
debug_log_sensitive_data(f"This was the user prompt\n {user_prompt}\n")
|
debug_log_sensitive_data(f"This was the user prompt\n {user_prompt}\n")
|
||||||
async with create_claude_client() as claude_client:
|
llm_client = llm_clients[optimize_model.model_type]
|
||||||
try:
|
try:
|
||||||
output = await claude_client.with_options(max_retries=2).chat.completions.create(
|
output = await llm_client.with_options(max_retries=2).chat.completions.create(
|
||||||
model=optimize_model.name, messages=messages, n=1
|
model=optimize_model.name, messages=messages, n=1
|
||||||
)
|
)
|
||||||
llm_cost = calculate_llm_cost(output, optimize_model)
|
llm_cost = calculate_llm_cost(output, optimize_model)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("Claude Code Generation error in refinement")
|
logging.exception("Claude Code Generation error in refinement")
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
debug_log_sensitive_data(f"Failed to generate code for source:\n{ctx.data.original_source_code}")
|
debug_log_sensitive_data(f"Failed to generate code for source:\n{ctx.data.original_source_code}")
|
||||||
return OptimizeErrorResponseSchema(error=str(e))
|
return OptimizeErrorResponseSchema(error=str(e))
|
||||||
debug_log_sensitive_data(f"ClaudeClient optimization response:\n{output.model_dump_json(indent=2)}")
|
debug_log_sensitive_data(f"ClaudeClient optimization response:\n{output.model_dump_json(indent=2)}")
|
||||||
if output.usage is not None:
|
if output.usage is not None:
|
||||||
ph(user_id, "refinement-usage", properties={"model": optimize_model.name, "usage": output.usage.json()})
|
ph(user_id, "refinement-usage", properties={"model": optimize_model.name, "usage": output.usage.json()})
|
||||||
|
|
@ -311,7 +311,8 @@ class Refinementschema(Schema):
|
||||||
|
|
||||||
@refinement_api.post("/", response={200: Refinementschema, 400: Refinementschema, 500: Refinementschema})
|
@refinement_api.post("/", response={200: Refinementschema, 400: Refinementschema, 500: Refinementschema})
|
||||||
async def refine(
|
async def refine(
|
||||||
request, data: list[RefinementRequestSchema]
|
request,
|
||||||
|
data: list[RefinementRequestSchema], # noqa: ANN001
|
||||||
) -> tuple[int, Refinementschema | OptimizeErrorResponseSchema]:
|
) -> tuple[int, Refinementschema | OptimizeErrorResponseSchema]:
|
||||||
ph(request.user, "aiservice-refinement-called")
|
ph(request.user, "aiservice-refinement-called")
|
||||||
ctx_data_list = [
|
ctx_data_list = [
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from aiservice.analytics.posthog import ph
|
from aiservice.analytics.posthog import ph
|
||||||
from aiservice.common_utils import validate_trace_id
|
from aiservice.common_utils import validate_trace_id
|
||||||
from aiservice.env_specific import debug_log_sensitive_data, openai_client
|
from aiservice.env_specific import create_llm_client, debug_log_sensitive_data, llm_clients
|
||||||
from aiservice.models.aimodels import LLM, RANKING_MODEL, calculate_llm_cost
|
from aiservice.models.aimodels import LLM, RANKING_MODEL, calculate_llm_cost
|
||||||
from log_features.log_event import update_optimization_cost
|
from log_features.log_event import update_optimization_cost
|
||||||
from log_features.log_features import log_features
|
from log_features.log_features import log_features
|
||||||
|
|
@ -109,12 +109,13 @@ async def rank_optimizations( # noqa: D417
|
||||||
| ChatCompletionToolMessageParam
|
| ChatCompletionToolMessageParam
|
||||||
| ChatCompletionFunctionMessageParam
|
| ChatCompletionFunctionMessageParam
|
||||||
] = [system_message, user_message]
|
] = [system_message, user_message]
|
||||||
|
llm_client = llm_clients[rank_model.model_type]
|
||||||
try:
|
try:
|
||||||
output = await openai_client.with_options(max_retries=2).chat.completions.create(
|
output = await llm_client.with_options(max_retries=2).chat.completions.create(
|
||||||
model=rank_model.name, messages=messages, n=1
|
model=rank_model.name, messages=messages, n=1
|
||||||
)
|
)
|
||||||
await update_optimization_cost(trace_id=data.trace_id, cost=calculate_llm_cost(output, rank_model))
|
await update_optimization_cost(trace_id=data.trace_id, cost=calculate_llm_cost(output, rank_model))
|
||||||
except Exception as e:
|
except Exception as e: # noqa: BLE001
|
||||||
debug_log_sensitive_data(f"Failed to generate new explanation, Error message: {e}")
|
debug_log_sensitive_data(f"Failed to generate new explanation, Error message: {e}")
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
return RankErrorResponseSchema(error=str(e))
|
return RankErrorResponseSchema(error=str(e))
|
||||||
|
|
@ -129,7 +130,7 @@ async def rank_optimizations( # noqa: D417
|
||||||
try:
|
try:
|
||||||
explanation_match = re.search(explain_regex_pattern, output.choices[0].message.content)
|
explanation_match = re.search(explain_regex_pattern, output.choices[0].message.content)
|
||||||
explanation = explanation_match.group(1)
|
explanation = explanation_match.group(1)
|
||||||
except:
|
except: # noqa: E722
|
||||||
# TODO add logging instead of print("No explanation found")
|
# TODO add logging instead of print("No explanation found")
|
||||||
explanation = ""
|
explanation = ""
|
||||||
# still doing stuff instead of returning coz ranking is important
|
# still doing stuff instead of returning coz ranking is important
|
||||||
|
|
@ -141,10 +142,10 @@ async def rank_optimizations( # noqa: D417
|
||||||
ranking_match = re.search(rank_regex_pattern, output.choices[0].message.content)
|
ranking_match = re.search(rank_regex_pattern, output.choices[0].message.content)
|
||||||
# TODO better parsing, could be only comma separated, need to handle all edge cases
|
# TODO better parsing, could be only comma separated, need to handle all edge cases
|
||||||
ranking = list(map(int, ranking_match.group(1).strip().split(",")))
|
ranking = list(map(int, ranking_match.group(1).strip().split(",")))
|
||||||
except:
|
except: # noqa: E722
|
||||||
# TODO add logging instead of print("No ranking found")
|
# TODO add logging instead of print("No ranking found")
|
||||||
return RankErrorResponseSchema(error="No ranking found")
|
return RankErrorResponseSchema(error="No ranking found")
|
||||||
if not sorted(ranking) == list(range(1, len(data.diffs) + 1)):
|
if sorted(ranking) != list(range(1, len(data.diffs) + 1)):
|
||||||
# TODO need to handle all edge cases
|
# TODO need to handle all edge cases
|
||||||
# TODO add logging instead of print("Invalid ranking")
|
# TODO add logging instead of print("Invalid ranking")
|
||||||
return RankErrorResponseSchema(error="No ranking found")
|
return RankErrorResponseSchema(error="No ranking found")
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,20 @@ import asyncio
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import SupportsIndex
|
from typing import TYPE_CHECKING, SupportsIndex
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
import stamina
|
import stamina
|
||||||
|
from aiservice.analytics.posthog import ph
|
||||||
|
from aiservice.common_utils import parse_python_version, safe_isort, should_hack_for_demo, validate_trace_id
|
||||||
|
from aiservice.env_specific import IS_PRODUCTION, create_llm_client, debug_log_sensitive_data, llm_clients
|
||||||
|
from aiservice.models.aimodels import EXECUTE_MODEL, calculate_llm_cost
|
||||||
|
from log_features.log_event import update_optimization_cost
|
||||||
|
from log_features.log_features import log_features
|
||||||
from ninja import NinjaAPI
|
from ninja import NinjaAPI
|
||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
from openai import OpenAIError
|
from openai import OpenAIError
|
||||||
|
|
||||||
from aiservice.analytics.posthog import ph
|
|
||||||
from aiservice.common_utils import parse_python_version, safe_isort, should_hack_for_demo, validate_trace_id
|
|
||||||
from aiservice.env_specific import IS_PRODUCTION, debug_log_sensitive_data, openai_client
|
|
||||||
from aiservice.models.aimodels import EXECUTE_MODEL, LLM, calculate_llm_cost
|
|
||||||
from authapp.auth import AuthBearer
|
|
||||||
from log_features.log_event import update_optimization_cost
|
|
||||||
from log_features.log_features import log_features
|
|
||||||
from testgen.instrumentation.edit_generated_test import parse_module_to_cst, replace_definition_with_import
|
from testgen.instrumentation.edit_generated_test import parse_module_to_cst, replace_definition_with_import
|
||||||
from testgen.instrumentation.instrument_new_tests import instrument_test_source
|
from testgen.instrumentation.instrument_new_tests import instrument_test_source
|
||||||
from testgen.models import (
|
from testgen.models import (
|
||||||
|
|
@ -34,6 +33,10 @@ from testgen.postprocessing.code_validator import has_test_functions, validate_t
|
||||||
from testgen.postprocessing.postprocess_pipeline import postprocessing_testgen_pipeline
|
from testgen.postprocessing.postprocess_pipeline import postprocessing_testgen_pipeline
|
||||||
from testgen.testgen_context import BaseTestGenContext, TestGenContextData
|
from testgen.testgen_context import BaseTestGenContext, TestGenContextData
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from aiservice.models.aimodels import LLM
|
||||||
|
from authapp.auth import AuthBearer
|
||||||
|
|
||||||
testgen_api = NinjaAPI(urls_namespace="testgen")
|
testgen_api = NinjaAPI(urls_namespace="testgen")
|
||||||
|
|
||||||
# Get the directory of the current file
|
# Get the directory of the current file
|
||||||
|
|
@ -111,7 +114,10 @@ To help unit test the function above, list diverse scenarios that the function s
|
||||||
package_comment = ""
|
package_comment = ""
|
||||||
# if unit_test_package == "pytest":
|
# if unit_test_package == "pytest":
|
||||||
# package_comment = "# below, each test case is represented by a tuple passed to the @pytest.mark.parametrize decorator"
|
# package_comment = "# below, each test case is represented by a tuple passed to the @pytest.mark.parametrize decorator"
|
||||||
execute_system_message = {"role": "system", "content": execute_system_prompt.format(function_name=ctx.data.qualified_name)}
|
execute_system_message = {
|
||||||
|
"role": "system",
|
||||||
|
"content": execute_system_prompt.format(function_name=ctx.data.qualified_name),
|
||||||
|
}
|
||||||
|
|
||||||
execute_messages = [execute_system_message, plan_user_message]
|
execute_messages = [execute_system_message, plan_user_message]
|
||||||
|
|
||||||
|
|
@ -196,7 +202,8 @@ async def generate_and_validate_test_code(
|
||||||
user_id: str,
|
user_id: str,
|
||||||
posthog_event_suffix: str,
|
posthog_event_suffix: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
response = await openai_client.with_options(max_retries=2).chat.completions.create(
|
llm_client = llm_clients[execute_model.model_type]
|
||||||
|
response = await llm_client.with_options(max_retries=2).chat.completions.create(
|
||||||
model=model.name, messages=messages, temperature=temperature
|
model=model.name, messages=messages, temperature=temperature
|
||||||
)
|
)
|
||||||
cost = calculate_llm_cost(response, execute_model) or 0.0
|
cost = calculate_llm_cost(response, execute_model) or 0.0
|
||||||
|
|
|
||||||
10
js/cf-api/Dockerfile
Normal file
10
js/cf-api/Dockerfile
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY /package*.json ./
|
||||||
|
RUN npm ci --only=production
|
||||||
|
COPY cf-api .
|
||||||
|
RUN mkdir ../common
|
||||||
|
COPY common ../common
|
||||||
|
RUN npm run build
|
||||||
|
EXPOSE 3001
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
|
|
@ -61,11 +61,18 @@ const initializeApp = async () => {
|
||||||
|
|
||||||
// Export the actual App instance, initialized based on environment
|
// Export the actual App instance, initialized based on environment
|
||||||
export const githubApp = await (async () => {
|
export const githubApp = await (async () => {
|
||||||
if (process.env.NODE_ENV === "test") {
|
// Check if GitHub App is configured
|
||||||
// In test environment, return a minimal mock that won't fail
|
const GH_APP_ID = process.env.GH_APP_ID
|
||||||
|
|
||||||
|
if (!GH_APP_ID || GH_APP_ID === "" || process.env.NODE_ENV === "test") {
|
||||||
|
console.log("caution: GitHub App not configured (GH_APP_ID missing)")
|
||||||
|
console.log("caution: PR creation and GitHub webhook features are disabled")
|
||||||
|
console.log("caution: CLI and optimization features will continue to work")
|
||||||
|
|
||||||
|
// Return a minimal mock that won't fail
|
||||||
return {
|
return {
|
||||||
octokit: {
|
octokit: {
|
||||||
request: async () => ({ data: { name: "Test App" } }),
|
request: async () => ({ data: { name: "GitHub App Disabled" } }),
|
||||||
log: {
|
log: {
|
||||||
debug: () => {},
|
debug: () => {},
|
||||||
},
|
},
|
||||||
|
|
@ -75,11 +82,14 @@ export const githubApp = await (async () => {
|
||||||
onAny: () => {},
|
onAny: () => {},
|
||||||
onError: () => {},
|
onError: () => {},
|
||||||
},
|
},
|
||||||
getInstallationOctokit: async () => ({}),
|
getInstallationOctokit: async () => {
|
||||||
|
throw new Error("GitHub App not configured. Set GH_APP_ID to enable PR creation.")
|
||||||
|
},
|
||||||
} as any as App
|
} as any as App
|
||||||
}
|
}
|
||||||
|
|
||||||
// In other environments, initialize normally
|
// In other environments, initialize normally
|
||||||
|
console.log(`GitHub App ID ${GH_APP_ID} detected, initializing...`)
|
||||||
const app = await initializeApp()
|
const app = await initializeApp()
|
||||||
|
|
||||||
console.log(`Github App Initialized`)
|
console.log(`Github App Initialized`)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import Stripe from "stripe"
|
import Stripe from "stripe"
|
||||||
|
|
||||||
if (!process.env.STRIPE_SECRET_KEY) {
|
if (!process.env.STRIPE_SECRET_KEY) {
|
||||||
throw new Error("STRIPE_SECRET_KEY is not set in environment variables")
|
console.warn("⚠️ STRIPE_SECRET_KEY not set, billing features will be disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
export const stripe = process.env.STRIPE_SECRET_KEY
|
||||||
apiVersion: "2025-08-27.basil",
|
? new Stripe(process.env.STRIPE_SECRET_KEY, {
|
||||||
})
|
apiVersion: "2025-08-27.basil",
|
||||||
|
})
|
||||||
|
: null
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue