8.7 KiB
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
- Upload Panel - Drag-and-drop X-ray upload
- 3D Viewer - Interactive brace model preview
- Analysis Results - Displays:
- Overall severity assessment
- Curve type classification
- Cobb angles (PT, MT, TL)
- Rigo-Chêneau classification
- Mesh information
- 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:
- Validate environment and request
- Get case from database
- Update status to
processing_brace - Download X-ray from S3
- Call GPU server
/analyze/upload - Download outputs from GPU server
/download/{caseId}/{filename} - Upload outputs to S3
- Update database with analysis results
- Return results with presigned URLs
Environment Variables:
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAMEBRACE_GENERATOR_URL- EC2 GPU server URLBUCKET_NAME- S3 bucket name
braceflow_get_brace_outputs
Located at: braceflow_lambda/braceflow_get_brace_outputs/index.mjs
Process:
- Get case from database
- List files in S3
cases/{caseId}/outputs/ - Generate presigned URLs for each file
- 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
- Go to http://localhost:5173/analyze
- Upload an X-ray image
- Wait for analysis to complete
- View results and download files
Troubleshooting
Common Issues
- CORS errors: Ensure API Gateway has CORS configured
- Timeout errors: Lambda timeout is 120s, may need increase for large images
- S3 access denied: Check Lambda role has S3 permissions
- GPU server unreachable: Check EC2 security group allows port 8000
Checking Lambda Logs
aws logs tail /aws/lambda/braceflow_invoke_brace_generator --follow