Initial commit - BraceIQMed platform with frontend, API, and brace generator
This commit is contained in:
382
frontend/BRACE_GENERATOR_INTEGRATION.md
Normal file
382
frontend/BRACE_GENERATOR_INTEGRATION.md
Normal file
@@ -0,0 +1,382 @@
|
||||
# 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:**
|
||||
```json
|
||||
{
|
||||
"caseId": "case-20260125-abc123"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Get Upload URL
|
||||
```
|
||||
POST /cases/{caseId}/upload-url
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"filename": "ap.jpg",
|
||||
"contentType": "image/jpeg"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"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:**
|
||||
```json
|
||||
{
|
||||
"experiment": "experiment_3",
|
||||
"config": {
|
||||
"brace_height_mm": 400,
|
||||
"torso_width_mm": 280,
|
||||
"torso_depth_mm": 200
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"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:**
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```powershell
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
aws logs tail /aws/lambda/braceflow_invoke_brace_generator --follow
|
||||
```
|
||||
Reference in New Issue
Block a user