Files
braceiqmed/frontend/BRACE_GENERATOR_INTEGRATION.md

8.7 KiB

Brace Generator Integration Guide

Overview

This document describes how the GPU-based brace generator is integrated into the Braceflow frontend via AWS Lambda functions.

Architecture

Frontend (React)
    │
    ├── Upload X-ray
    │   └── POST /cases → Create case
    │   └── POST /cases/{caseId}/upload-url → Get presigned URL
    │   └── PUT to S3 → Upload file directly
    │
    └── Generate Brace
        └── POST /cases/{caseId}/generate-brace
            └── Lambda: braceflow_invoke_brace_generator
                └── Download image from S3
                └── Call EC2 GPU server /analyze/upload
                └── Download outputs from GPU server
                └── Upload outputs to S3
                └── Update database with results
                └── Return results with presigned URLs

API Endpoints

1. Create Case

POST /cases

Response:

{
  "caseId": "case-20260125-abc123"
}

2. Get Upload URL

POST /cases/{caseId}/upload-url

Request Body:

{
  "filename": "ap.jpg",
  "contentType": "image/jpeg"
}

Response:

{
  "url": "https://braceflow-uploads-xxx.s3.amazonaws.com/...",
  "s3Key": "cases/case-xxx/input/ap.jpg"
}

3. Generate Brace

POST /cases/{caseId}/generate-brace

Request Body:

{
  "experiment": "experiment_3",
  "config": {
    "brace_height_mm": 400,
    "torso_width_mm": 280,
    "torso_depth_mm": 200
  }
}

Response:

{
  "caseId": "case-20260125-abc123",
  "status": "brace_generated",
  "experiment": "experiment_3",
  "model": "ScolioVis",
  "vertebrae_detected": 17,
  "cobb_angles": {
    "PT": 12.5,
    "MT": 28.3,
    "TL": 15.2
  },
  "curve_type": "S-shaped",
  "rigo_classification": {
    "type": "A3",
    "description": "Major thoracic with compensatory lumbar"
  },
  "mesh": {
    "vertices": 6204,
    "faces": 12404
  },
  "outputs": {
    "stl": { "s3Key": "cases/.../brace.stl", "url": "https://..." },
    "ply": { "s3Key": "cases/.../brace.ply", "url": "https://..." },
    "visualization": { "s3Key": "cases/.../viz.png", "url": "https://..." },
    "landmarks": { "s3Key": "cases/.../landmarks.json", "url": "https://..." }
  },
  "processing_time_ms": 3250
}

4. Get Brace Outputs

GET /cases/{caseId}/brace-outputs

Response:

{
  "caseId": "case-20260125-abc123",
  "status": "brace_generated",
  "analysis": {
    "experiment": "experiment_3",
    "model": "ScolioVis",
    "cobb_angles": { "PT": 12.5, "MT": 28.3, "TL": 15.2 },
    "curve_type": "S-shaped",
    "rigo_classification": { "type": "A3", "description": "..." }
  },
  "outputs": [
    {
      "filename": "brace.stl",
      "type": "stl",
      "s3Key": "cases/.../brace.stl",
      "size": 1234567,
      "url": "https://...",
      "expiresIn": 3600
    }
  ]
}

Frontend Implementation

API Client (src/api/braceflowApi.ts)

The API client includes these functions:

// Create a new case
export async function createCase(body?: { notes?: string }): Promise<{ caseId: string }>;

// Get presigned URL for S3 upload
export async function getUploadUrl(caseId: string, filename: string, contentType: string): 
  Promise<{ url: string; s3Key: string }>;

// Upload file directly to S3
export async function uploadToS3(presignedUrl: string, file: File): Promise<void>;

// Invoke brace generator Lambda
export async function generateBrace(caseId: string, options?: { 
  experiment?: string; 
  config?: Record<string, unknown> 
}): Promise<GenerateBraceResponse>;

// Get brace outputs with presigned URLs
export async function getBraceOutputs(caseId: string): Promise<BraceOutputsResponse>;

// Full workflow helper
export async function analyzeXray(file: File, options?: { 
  experiment?: string; 
  config?: Record<string, unknown> 
}): Promise<{ caseId: string; result: GenerateBraceResponse }>;

Types

export type CobbAngles = {
  PT?: number;
  MT?: number;
  TL?: number;
};

export type RigoClassification = {
  type: string;
  description: string;
  curve_pattern?: string;
};

export type AnalysisResult = {
  experiment?: string;
  model?: string;
  vertebrae_detected?: number;
  cobb_angles?: CobbAngles;
  curve_type?: string;
  rigo_classification?: RigoClassification;
  mesh_info?: { vertices?: number; faces?: number };
  outputs?: Record<string, { s3Key: string; url: string }>;
  processing_time_ms?: number;
};

export type BraceOutput = {
  filename: string;
  type: "stl" | "ply" | "obj" | "image" | "json" | "other";
  s3Key: string;
  size: number;
  url: string;
  expiresIn: number;
};

Routes

Route Page Description
/analyze BraceAnalysisPage New analysis with X-ray upload
/cases/:caseId/analysis BraceAnalysisPage View existing case analysis
/generate ShellGenerationPage Direct brace generation (legacy)

Page: BraceAnalysisPage

Located at src/pages/BraceAnalysisPage.tsx

Features

  1. Upload Panel - Drag-and-drop X-ray upload
  2. 3D Viewer - Interactive brace model preview
  3. Analysis Results - Displays:
    • Overall severity assessment
    • Curve type classification
    • Cobb angles (PT, MT, TL)
    • Rigo-Chêneau classification
    • Mesh information
  4. Downloads - All generated files with presigned S3 URLs

Layout

Three-column layout:

  • Left: Upload panel with case ID display
  • Center: 3D brace viewer with processing info
  • Right: Analysis results and download links

Components

Reusable Components

Component Location Description
UploadPanel src/components/rigo/UploadPanel.tsx Drag-and-drop file upload
BraceViewer src/components/rigo/BraceViewer.tsx 3D model viewer (React Three Fiber)
AnalysisResults src/components/rigo/AnalysisResults.tsx Analysis display component

Lambda Functions

braceflow_invoke_brace_generator

Located at: braceflow_lambda/braceflow_invoke_brace_generator/index.mjs

Process:

  1. Validate environment and request
  2. Get case from database
  3. Update status to processing_brace
  4. Download X-ray from S3
  5. Call GPU server /analyze/upload
  6. Download outputs from GPU server /download/{caseId}/{filename}
  7. Upload outputs to S3
  8. Update database with analysis results
  9. Return results with presigned URLs

Environment Variables:

  • DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME
  • BRACE_GENERATOR_URL - EC2 GPU server URL
  • BUCKET_NAME - S3 bucket name

braceflow_get_brace_outputs

Located at: braceflow_lambda/braceflow_get_brace_outputs/index.mjs

Process:

  1. Get case from database
  2. List files in S3 cases/{caseId}/outputs/
  3. Generate presigned URLs for each file
  4. Return files list with analysis data

S3 Structure

braceflow-uploads-{date}/
├── cases/
│   └── {caseId}/
│       ├── input/
│       │   └── ap.jpg          # Original X-ray
│       └── outputs/
│           ├── brace_{caseId}.stl        # 3D printable model
│           ├── brace_{caseId}_adaptive.ply  # Adaptive mesh
│           ├── brace_{caseId}.png        # Visualization
│           └── brace_{caseId}.json       # Landmarks data

Database Schema

CREATE TABLE brace_cases (
  case_id VARCHAR(64) PRIMARY KEY,
  status ENUM('created', 'processing_brace', 'brace_generated', 'brace_failed'),
  current_step VARCHAR(64),
  analysis_result JSON,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Deployment

Deploy Lambda Functions

cd braceflow_lambda/deploy
.\deploy-brace-generator-lambdas.ps1 -BraceGeneratorUrl "http://YOUR_EC2_IP:8000"

Add API Gateway Routes

POST /cases/{caseId}/generate-brace → braceflow_invoke_brace_generator
GET  /cases/{caseId}/brace-outputs  → braceflow_get_brace_outputs

Running Locally

Frontend

cd braceflow
npm install
npm run dev
# Open http://localhost:5173

Navigate to /analyze to use the new brace analysis page.

Testing

  1. Go to http://localhost:5173/analyze
  2. Upload an X-ray image
  3. Wait for analysis to complete
  4. View results and download files

Troubleshooting

Common Issues

  1. CORS errors: Ensure API Gateway has CORS configured
  2. Timeout errors: Lambda timeout is 120s, may need increase for large images
  3. S3 access denied: Check Lambda role has S3 permissions
  4. GPU server unreachable: Check EC2 security group allows port 8000

Checking Lambda Logs

aws logs tail /aws/lambda/braceflow_invoke_brace_generator --follow