Generating a Report
This guide walks you through generating a PDF technical report from vehicle damage photos. By the end, you'll have a downloadable report with Delta-V calculations, damage analysis, and crash dynamics.
What You'll Build
The technical report workflow creates a professional PDF document:
| Step | Action | Description |
|---|---|---|
| 1 | Create Case | Organize files under a case |
| 2 | Upload Photos | Upload vehicle damage images |
| 3 | Create Report | Submit vehicle details for analysis |
| 4 | Poll for Completion | Monitor progress (2-5 min) |
| 5 | Download PDF | Get the completed report |
What You Need
Required:
- At least one vehicle damage photo (JPEG or PNG)
Optional (but recommended):
- Multiple angles: front, rear, sides, close-ups of damage
- Vehicle information (make, model, year)
- Accident details (date, description, location)
- Defendant vehicle photos (for two-vehicle crashes)
Step 1: Create a Case
First, create a case to organize your files and reports:
- Go
- TypeScript
package main
import (
"context"
"fmt"
"log"
"os"
silentwitness "github.com/silentwitness/sw-go-sdk"
)
func main() {
// Create client
client := silentwitness.NewClient(silentwitness.Config{
APIKey: os.Getenv("SW_API_KEY"),
})
defer client.Close()
ctx := context.Background()
// Create a case
caseResp, err := client.CreateCase(ctx, &silentwitness.CaseParams{
Name: silentwitness.String("Smith v. Johnson"),
ClientName: silentwitness.String("Jane Smith"),
})
if err != nil {
log.Fatalf("Failed to create case: %v", err)
}
fmt.Printf("Created case: %s\n", caseResp.ID)
}
import { SilentWitnessClient } from "@silentwitness/sdk";
const client = new SilentWitnessClient({
apiKey: process.env.SW_API_KEY
});
// Create a case
const caseResp = await client.createCase({
name: "Smith v. Johnson",
clientName: "Jane Smith"
});
console.log(`Created case: ${caseResp.id}`);
Step 2: Upload Vehicle Photos
Upload the vehicle damage photos. Use the purpose field to indicate which vehicle the photos belong to:
- Go
- TypeScript
// Load the photo
photoData, err := os.ReadFile("vehicle-damage-front.jpg")
if err != nil {
log.Fatalf("Failed to read photo: %v", err)
}
// Upload it
upload, err := client.UploadFile(ctx, &silentwitness.UploadFileParams{
CaseID: caseResp.ID,
Filename: "vehicle-damage-front.jpg",
Content: photoData,
Purpose: silentwitness.FilePurposeCrashPlaintiff,
})
if err != nil {
log.Fatalf("Upload failed: %v", err)
}
fmt.Printf("Uploaded file: %s\n", upload.FileID)
import fs from "fs";
// Load the photo
const photoData = fs.readFileSync("vehicle-damage-front.jpg");
// Upload it
const upload = await client.uploadFile({
caseId: caseResp.id,
filename: "vehicle-damage-front.jpg",
content: photoData,
purpose: "crash_analysis_plaintiff"
});
console.log(`Uploaded file: ${upload.fileId}`);
Purpose Values
| Purpose | Description |
|---|---|
crash_analysis_plaintiff | Photos of the plaintiff's vehicle |
crash_analysis_defendant | Photos of the defendant's vehicle |
Upload 4-8 photos per vehicle for best results. Include:
- Front, rear, and side views
- Close-ups of damage areas
- Interior damage if applicable
Step 3: Create the Report
Submit the vehicle details and photo references to generate the report. The API will use ML to compute Delta-V, PDOF, and impact type from your photos.
- Go
- TypeScript
response, err := client.CreateReport(ctx, &silentwitness.CreateReportParams{
CaseID: caseResp.ID,
Type: silentwitness.ReportTypeTechnicalReport,
Plaintiff: &silentwitness.VehicleDataParams{
ImageFileIds: []string{upload.FileID},
VehicleMaker: silentwitness.String("Toyota"),
VehicleModel: silentwitness.String("Camry"),
VehicleYear: silentwitness.String("2020"),
VehicleType: silentwitness.String("sedan"),
// Seatbelt/airbag data is per-occupant - see occupants field
},
AccidentDescription: silentwitness.String("Rear-end collision at intersection"),
AccidentDate: silentwitness.String("2024-03-15"),
})
if err != nil {
log.Fatalf("Report creation failed: %v", err)
}
fmt.Printf("Report created: %s\n", response.ReportID)
const response = await client.createReport({
caseId: caseResp.id,
type: "technical_report",
plaintiff: {
imageFileIds: [upload.fileId],
vehicleMaker: "Toyota",
vehicleModel: "Camry",
vehicleYear: "2020",
vehicleType: "sedan"
// Seatbelt/airbag data is per-occupant - see occupants field
},
accidentDescription: "Rear-end collision at intersection",
accidentDate: "2024-03-15"
});
console.log(`Report created: ${response.reportId}`);
Required vs Optional Fields
Required:
caseId- The case to associate the report withtype- The report type (technical_report)plaintiff.imageFileIds- At least one uploaded photo ID (oredrFileId)
Optional:
plaintiff.vehicleMaker,vehicleModel,vehicleYear,vehicleTypedefendant- Second vehicle data for two-vehicle crashesaccidentDescription,accidentDate,accidentTime,accidentLocationoccupants- For integrated biomechanics analysis (includes per-occupantseatbeltWornandairbagDeployedfields)
Step 4: Poll for Completion
Report generation takes 2-5 minutes. Poll the status every 5 seconds:
- Go
- TypeScript
import "time"
reportID := response.ReportID
for {
report, err := client.GetReport(ctx, reportID)
if err != nil {
log.Fatalf("Failed to check status: %v", err)
}
fmt.Printf("Status: %s\n", report.Status)
switch report.Status {
case silentwitness.ReportStatusCompleted:
fmt.Printf("Report ready: %s\n", *report.ReportURL)
return
case silentwitness.ReportStatusFailed:
log.Fatal("Report generation failed")
}
time.Sleep(5 * time.Second)
}
const reportId = response.reportId;
while (true) {
const report = await client.getReport(reportId);
console.log(`Status: ${report.status}`);
if (report.status === "completed") {
console.log(`Report ready: ${report.reportUrl}`);
break;
} else if (report.status === "failed") {
throw new Error("Report generation failed");
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
Status Values
| Status | Description |
|---|---|
pending | Queued for processing |
processing | Currently generating |
completed | Report ready at reportUrl |
failed | Generation failed |
What's in the Report
The completed PDF includes:
| Section | Contents |
|---|---|
| Delta-V Analysis | Change in velocity calculations (computed by ML) |
| PDOF Analysis | Principal Direction of Force (impact angle) |
| Impact Classification | Impact type and collision type (computed from PDOF) |
| Damage Assessment | Photo-based damage severity analysis |
| Methodology | Explanation of analysis approach |
Complete Code Example
Here's the full code putting it all together:
- Go
- TypeScript
package main
import (
"context"
"fmt"
"log"
"os"
"time"
silentwitness "github.com/silentwitness/sw-go-sdk"
)
func main() {
// Create client
client := silentwitness.NewClient(silentwitness.Config{
APIKey: os.Getenv("SW_API_KEY"),
})
defer client.Close()
ctx := context.Background()
// Step 1: Create a case
caseResp, err := client.CreateCase(ctx, &silentwitness.CaseParams{
Name: silentwitness.String("Smith v. Johnson"),
ClientName: silentwitness.String("Jane Smith"),
})
if err != nil {
log.Fatalf("Failed to create case: %v", err)
}
fmt.Printf("Created case: %s\n", caseResp.ID)
// Step 2: Upload vehicle photos
photoData, err := os.ReadFile("vehicle-damage-front.jpg")
if err != nil {
log.Fatalf("Failed to read photo: %v", err)
}
upload, err := client.UploadFile(ctx, &silentwitness.UploadFileParams{
CaseID: caseResp.ID,
Filename: "vehicle-damage-front.jpg",
Content: photoData,
Purpose: silentwitness.FilePurposeCrashPlaintiff,
})
if err != nil {
log.Fatalf("Upload failed: %v", err)
}
fmt.Printf("Uploaded file: %s\n", upload.FileID)
// Step 3: Create technical report
response, err := client.CreateReport(ctx, &silentwitness.CreateReportParams{
CaseID: caseResp.ID,
Type: silentwitness.ReportTypeTechnicalReport,
Plaintiff: &silentwitness.VehicleDataParams{
ImageFileIds: []string{upload.FileID},
VehicleMaker: silentwitness.String("Toyota"),
VehicleModel: silentwitness.String("Camry"),
VehicleYear: silentwitness.String("2020"),
VehicleType: silentwitness.String("sedan"),
},
AccidentDescription: silentwitness.String("Rear-end collision at intersection"),
AccidentDate: silentwitness.String("2024-03-15"),
})
if err != nil {
log.Fatalf("Report creation failed: %v", err)
}
fmt.Printf("Report created: %s\n", response.ReportID)
// Step 4: Poll for completion
reportID := response.ReportID
for {
report, err := client.GetReport(ctx, reportID)
if err != nil {
log.Fatalf("Failed to check status: %v", err)
}
fmt.Printf("Status: %s\n", report.Status)
if report.Status == silentwitness.ReportStatusCompleted {
fmt.Printf("Report ready: %s\n", *report.ReportURL)
break
} else if report.Status == silentwitness.ReportStatusFailed {
log.Fatal("Report generation failed")
}
time.Sleep(5 * time.Second)
}
}
import { SilentWitnessClient } from "@silentwitness/sdk";
import fs from "fs";
async function main() {
// Create client
const client = new SilentWitnessClient({
apiKey: process.env.SW_API_KEY
});
// Step 1: Create a case
const caseResp = await client.createCase({
name: "Smith v. Johnson",
clientName: "Jane Smith"
});
console.log(`Created case: ${caseResp.id}`);
// Step 2: Upload vehicle photos
const photoData = fs.readFileSync("vehicle-damage-front.jpg");
const upload = await client.uploadFile({
caseId: caseResp.id,
filename: "vehicle-damage-front.jpg",
content: photoData,
purpose: "crash_analysis_plaintiff"
});
console.log(`Uploaded file: ${upload.fileId}`);
// Step 3: Create technical report
const response = await client.createReport({
caseId: caseResp.id,
type: "technical_report",
plaintiff: {
imageFileIds: [upload.fileId],
vehicleMaker: "Toyota",
vehicleModel: "Camry",
vehicleYear: "2020",
vehicleType: "sedan"
},
accidentDescription: "Rear-end collision at intersection",
accidentDate: "2024-03-15"
});
console.log(`Report created: ${response.reportId}`);
// Step 4: Poll for completion
const reportId = response.reportId;
while (true) {
const report = await client.getReport(reportId);
console.log(`Status: ${report.status}`);
if (report.status === "completed") {
console.log(`Report ready: ${report.reportUrl}`);
break;
} else if (report.status === "failed") {
throw new Error("Report generation failed");
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
main().catch(console.error);
Troubleshooting
File Upload Issues
- Maximum file size: 50MB per file
- Supported formats: JPEG, PNG
- Ensure the case exists before uploading files
Report Creation Issues
- At least one plaintiff photo (or EDR file) is required
- Vehicle year must be 4 digits (e.g., "2020")
- Date format: YYYY-MM-DD (e.g., "2024-03-15")
Polling Tips
- Poll every 3-5 seconds
- Reports typically complete in 2-5 minutes
- Implement exponential backoff for production use
Next Steps
- Technical Report API Reference - Full API documentation
- File Management - Learn about file operations
- Biomechanics Analysis - Add occupant injury analysis