@rexai/pulse-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -0
- package/dist/index.d.mts +432 -0
- package/dist/index.d.ts +432 -0
- package/dist/index.js +850 -0
- package/dist/index.mjs +805 -0
- package/dist/styles.css +436 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @rexai/pulse-react
|
|
2
|
+
|
|
3
|
+
React SDK for PulseAI - measure vital signs from any camera using remote photoplethysmography (rPPG).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @rexai/pulse-react
|
|
9
|
+
# or
|
|
10
|
+
yarn add @rexai/pulse-react
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @rexai/pulse-react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { PulseScanner, VitalsCard } from '@rexai/pulse-react';
|
|
19
|
+
import '@rexai/pulse-react/styles.css';
|
|
20
|
+
import { useState } from 'react';
|
|
21
|
+
|
|
22
|
+
function App() {
|
|
23
|
+
const [vitals, setVitals] = useState(null);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div>
|
|
27
|
+
<PulseScanner
|
|
28
|
+
apiKey="pk_live_YOUR_API_KEY"
|
|
29
|
+
duration={10}
|
|
30
|
+
showMesh={true} // Show face mesh overlay
|
|
31
|
+
onResult={(result) => setVitals(result)}
|
|
32
|
+
onError={(err) => console.error(err)}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
{vitals && (
|
|
36
|
+
<VitalsCard
|
|
37
|
+
heartRate={vitals.heart_rate}
|
|
38
|
+
spo2={vitals.spo2}
|
|
39
|
+
stressIndex={vitals.stress_index}
|
|
40
|
+
hrvSdnn={vitals.hrv_sdnn}
|
|
41
|
+
/>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Note:** The SDK automatically uses your `VITE_API_URL` environment variable. No need to pass `apiUrl` if it's already configured.
|
|
49
|
+
|
|
50
|
+
## Components
|
|
51
|
+
|
|
52
|
+
### PulseScanner
|
|
53
|
+
|
|
54
|
+
The main component for capturing and analyzing vital signs.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<PulseScanner
|
|
58
|
+
apiKey="pk_live_..." // Required: Your API key
|
|
59
|
+
duration={10} // Scan duration in seconds (default: 10)
|
|
60
|
+
onResult={(vitals) => {...}} // Called with results
|
|
61
|
+
onError={(error) => {...}} // Called on error
|
|
62
|
+
theme="light" // "light" | "dark" | "minimal"
|
|
63
|
+
showPreview={true} // Show camera preview
|
|
64
|
+
showOverlay={true} // Show face detection overlay
|
|
65
|
+
showMesh={true} // Show face mesh lines (default: false)
|
|
66
|
+
showCountdown={true} // Show countdown during recording
|
|
67
|
+
userData={{ // Optional user data for calibration
|
|
68
|
+
age: 30,
|
|
69
|
+
sex: 'male'
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### VitalsCard
|
|
75
|
+
|
|
76
|
+
Display component for vital sign results.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<VitalsCard
|
|
80
|
+
heartRate={72}
|
|
81
|
+
spo2={98}
|
|
82
|
+
stressIndex={25}
|
|
83
|
+
hrvSdnn={45}
|
|
84
|
+
respiratoryRate={16}
|
|
85
|
+
bloodPressure={{ systolic: 120, diastolic: 80 }}
|
|
86
|
+
recoveryScore={85}
|
|
87
|
+
showAll={true} // Show extended metrics
|
|
88
|
+
compact={false} // Compact layout
|
|
89
|
+
theme="light" // "light" | "dark"
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API Client
|
|
94
|
+
|
|
95
|
+
For programmatic access without the UI components:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { PulseClient } from '@rexai/pulse-react';
|
|
99
|
+
|
|
100
|
+
const client = new PulseClient({
|
|
101
|
+
apiKey: 'pk_live_YOUR_API_KEY'
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Analyze a video blob
|
|
105
|
+
const vitals = await client.analyze({
|
|
106
|
+
video: videoBlob,
|
|
107
|
+
age: 30,
|
|
108
|
+
sex: 'male'
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
console.log(vitals.heart_rate); // 72
|
|
112
|
+
console.log(vitals.spo2); // 98
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Hooks
|
|
116
|
+
|
|
117
|
+
For building custom UI:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useCamera, useFaceDetection, useRecording } from '@rexai/pulse-react';
|
|
121
|
+
|
|
122
|
+
function CustomScanner() {
|
|
123
|
+
const { videoRef, isActive, start, stop } = useCamera();
|
|
124
|
+
const { detected, qualityMessage, isQualityGood } = useFaceDetection(videoRef.current);
|
|
125
|
+
const { isRecording, timeLeft, blob, start: startRecording } = useRecording(stream);
|
|
126
|
+
|
|
127
|
+
// Build your own UI...
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Vitals Returned
|
|
132
|
+
|
|
133
|
+
| Metric | Type | Description |
|
|
134
|
+
|--------|------|-------------|
|
|
135
|
+
| `heart_rate` | number | Heart rate in BPM |
|
|
136
|
+
| `spo2` | number | Oxygen saturation % |
|
|
137
|
+
| `hrv_sdnn` | number | HRV (SDNN) in ms |
|
|
138
|
+
| `hrv_rmssd` | number | HRV (RMSSD) in ms |
|
|
139
|
+
| `stress_index` | number | Stress index (0-100) |
|
|
140
|
+
| `respiratory_rate` | number | Breaths per minute |
|
|
141
|
+
| `blood_pressure` | object | Estimated BP (systolic/diastolic) |
|
|
142
|
+
| `recovery_score` | number | Recovery score % |
|
|
143
|
+
| `vascular_age` | number | Estimated vascular age |
|
|
144
|
+
|
|
145
|
+
## Getting an API Key
|
|
146
|
+
|
|
147
|
+
1. Visit [pulseai.com/developer/login](https://pulseai.com/developer/login)
|
|
148
|
+
2. Sign in with Google
|
|
149
|
+
3. Generate an API key from the dashboard
|
|
150
|
+
|
|
151
|
+
## Support
|
|
152
|
+
|
|
153
|
+
- Documentation: [pulseai.com/docs](https://pulseai.com/docs)
|
|
154
|
+
- Email: support@pulseai.com
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import React$1 from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PulseAI SDK Type Definitions
|
|
5
|
+
*/
|
|
6
|
+
interface BloodPressure {
|
|
7
|
+
systolic: number;
|
|
8
|
+
diastolic: number;
|
|
9
|
+
}
|
|
10
|
+
interface ArrhythmiaResult {
|
|
11
|
+
has_arrhythmia: boolean;
|
|
12
|
+
irregularity_score: number;
|
|
13
|
+
details: string;
|
|
14
|
+
}
|
|
15
|
+
interface VisualAnalysis {
|
|
16
|
+
jaundice_risk: 'Low' | 'Medium' | 'High';
|
|
17
|
+
anemia_risk: 'Low' | 'Medium' | 'High';
|
|
18
|
+
bilirubin_proxy: number;
|
|
19
|
+
pallor_index: number;
|
|
20
|
+
hydration_level?: string;
|
|
21
|
+
hydration_score?: number;
|
|
22
|
+
fatigue_indicators?: {
|
|
23
|
+
eye_redness: number;
|
|
24
|
+
under_eye_darkness: number;
|
|
25
|
+
puffiness: number;
|
|
26
|
+
overall_fatigue: string;
|
|
27
|
+
};
|
|
28
|
+
skin_health?: {
|
|
29
|
+
evenness: number;
|
|
30
|
+
redness: number;
|
|
31
|
+
oiliness_proxy: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
interface MentalWellness {
|
|
35
|
+
wellness_score: number;
|
|
36
|
+
level: string;
|
|
37
|
+
emotion: string;
|
|
38
|
+
emotion_confidence?: number;
|
|
39
|
+
blink_rate_per_min: number;
|
|
40
|
+
gaze_stability: number;
|
|
41
|
+
gaze_direction?: string;
|
|
42
|
+
components: {
|
|
43
|
+
blink_score: number;
|
|
44
|
+
gaze_score: number;
|
|
45
|
+
emotion_score: number;
|
|
46
|
+
hrv_score: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface CompositeScores {
|
|
50
|
+
cardio_score: number;
|
|
51
|
+
resilience_score: number;
|
|
52
|
+
metabolic_score: number;
|
|
53
|
+
vitality_score: number;
|
|
54
|
+
}
|
|
55
|
+
interface BMIEstimate {
|
|
56
|
+
value: number;
|
|
57
|
+
category: string;
|
|
58
|
+
fwhr: number;
|
|
59
|
+
confidence?: string;
|
|
60
|
+
method?: string;
|
|
61
|
+
}
|
|
62
|
+
interface VitalsResult {
|
|
63
|
+
heart_rate: number;
|
|
64
|
+
respiratory_rate: number;
|
|
65
|
+
hrv_sdnn: number;
|
|
66
|
+
hrv_rmssd: number;
|
|
67
|
+
recovery_score: number;
|
|
68
|
+
stress_index: number;
|
|
69
|
+
arrhythmia: ArrhythmiaResult;
|
|
70
|
+
rsa_amplitude: number;
|
|
71
|
+
blood_pressure: BloodPressure;
|
|
72
|
+
spo2: number;
|
|
73
|
+
signal_snippet: number[];
|
|
74
|
+
vascular_age: number;
|
|
75
|
+
bmi_est: BMIEstimate;
|
|
76
|
+
manual_bmi?: number;
|
|
77
|
+
metabolic_score: number;
|
|
78
|
+
skin_temperature: number;
|
|
79
|
+
composite_scores: CompositeScores;
|
|
80
|
+
visual_analysis?: VisualAnalysis;
|
|
81
|
+
mental_wellness?: MentalWellness;
|
|
82
|
+
fusion_weights: Record<string, number>;
|
|
83
|
+
}
|
|
84
|
+
interface BeautySummary {
|
|
85
|
+
overall_score: number;
|
|
86
|
+
skin_age: number;
|
|
87
|
+
}
|
|
88
|
+
interface BeautySurface {
|
|
89
|
+
texture: number;
|
|
90
|
+
hydration: number;
|
|
91
|
+
foundation_hex: string;
|
|
92
|
+
undertone: string;
|
|
93
|
+
acne_count: number;
|
|
94
|
+
acne_severity: string;
|
|
95
|
+
wrinkle_severity: string;
|
|
96
|
+
wrinkle_density: number;
|
|
97
|
+
oiliness_index: number;
|
|
98
|
+
matches: string;
|
|
99
|
+
skin_health: {
|
|
100
|
+
evenness: number;
|
|
101
|
+
redness: number;
|
|
102
|
+
oiliness_proxy: number;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
interface BeautyGeometry {
|
|
106
|
+
symmetry_score: number;
|
|
107
|
+
face_shape: string;
|
|
108
|
+
eye_openness: number;
|
|
109
|
+
ptosis_indices: {
|
|
110
|
+
status: string;
|
|
111
|
+
youth_ratio?: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
interface BeautyPhysiology {
|
|
115
|
+
glow_index: number;
|
|
116
|
+
stress_level: string;
|
|
117
|
+
elasticity: number;
|
|
118
|
+
}
|
|
119
|
+
interface BeautyRecommendations {
|
|
120
|
+
routine: string[];
|
|
121
|
+
tips: string[];
|
|
122
|
+
}
|
|
123
|
+
interface BeautyResult {
|
|
124
|
+
summary: BeautySummary;
|
|
125
|
+
surface: BeautySurface;
|
|
126
|
+
geometry: BeautyGeometry;
|
|
127
|
+
physiology: BeautyPhysiology;
|
|
128
|
+
recommendations: BeautyRecommendations;
|
|
129
|
+
}
|
|
130
|
+
interface APIResponse<T> {
|
|
131
|
+
status: 'success' | 'error';
|
|
132
|
+
data: T;
|
|
133
|
+
meta?: {
|
|
134
|
+
privacy: string;
|
|
135
|
+
};
|
|
136
|
+
message?: string;
|
|
137
|
+
}
|
|
138
|
+
interface APIError {
|
|
139
|
+
detail: string;
|
|
140
|
+
status_code?: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Props for PulseScanner component
|
|
145
|
+
*/
|
|
146
|
+
interface PulseScannerProps {
|
|
147
|
+
/** Your PulseAI API key */
|
|
148
|
+
apiKey: string;
|
|
149
|
+
/** API URL (optional - defaults to VITE_API_URL env var) */
|
|
150
|
+
apiUrl?: string;
|
|
151
|
+
/** Scan duration in seconds (default: 10) */
|
|
152
|
+
duration?: number;
|
|
153
|
+
/** Callback when vitals are successfully extracted */
|
|
154
|
+
onResult: (vitals: VitalsResult) => void;
|
|
155
|
+
/** Callback on error */
|
|
156
|
+
onError?: (error: Error) => void;
|
|
157
|
+
/** Callback for status updates */
|
|
158
|
+
onStatusChange?: (status: ScannerStatus) => void;
|
|
159
|
+
/** Show camera preview (default: true) */
|
|
160
|
+
showPreview?: boolean;
|
|
161
|
+
/** Show face detection overlay (default: true) */
|
|
162
|
+
showOverlay?: boolean;
|
|
163
|
+
/** Show face mesh lines overlay (default: false) */
|
|
164
|
+
showMesh?: boolean;
|
|
165
|
+
/** Show countdown during recording (default: true) */
|
|
166
|
+
showCountdown?: boolean;
|
|
167
|
+
/** Custom CSS class */
|
|
168
|
+
className?: string;
|
|
169
|
+
/** Theme variant */
|
|
170
|
+
theme?: 'light' | 'dark' | 'minimal';
|
|
171
|
+
/** User data for calibration */
|
|
172
|
+
userData?: {
|
|
173
|
+
age?: number;
|
|
174
|
+
sex?: 'male' | 'female';
|
|
175
|
+
weight?: number;
|
|
176
|
+
height?: number;
|
|
177
|
+
};
|
|
178
|
+
/** Auto-start camera on mount */
|
|
179
|
+
autoStart?: boolean;
|
|
180
|
+
}
|
|
181
|
+
type ScannerStatus = 'idle' | 'loading' | 'ready' | 'recording' | 'uploading' | 'analyzing' | 'complete' | 'error';
|
|
182
|
+
/**
|
|
183
|
+
* PulseScanner - Main component for capturing and analyzing vitals
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```tsx
|
|
187
|
+
* <PulseScanner
|
|
188
|
+
* apiKey="pk_live_..."
|
|
189
|
+
* duration={10}
|
|
190
|
+
* onResult={(vitals) => console.log(vitals)}
|
|
191
|
+
* onError={(err) => console.error(err)}
|
|
192
|
+
* />
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
declare const PulseScanner: React$1.FC<PulseScannerProps>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Props for VitalsCard component
|
|
199
|
+
*/
|
|
200
|
+
interface VitalsCardProps {
|
|
201
|
+
/** Heart rate in BPM */
|
|
202
|
+
heartRate?: number;
|
|
203
|
+
/** Oxygen saturation percentage */
|
|
204
|
+
spo2?: number;
|
|
205
|
+
/** Stress index (0-100) */
|
|
206
|
+
stressIndex?: number;
|
|
207
|
+
/** HRV SDNN in milliseconds */
|
|
208
|
+
hrvSdnn?: number;
|
|
209
|
+
/** HRV RMSSD in milliseconds */
|
|
210
|
+
hrvRmssd?: number;
|
|
211
|
+
/** Respiratory rate per minute */
|
|
212
|
+
respiratoryRate?: number;
|
|
213
|
+
/** Blood pressure readings */
|
|
214
|
+
bloodPressure?: BloodPressure;
|
|
215
|
+
/** Recovery score percentage */
|
|
216
|
+
recoveryScore?: number;
|
|
217
|
+
/** Show loading state */
|
|
218
|
+
loading?: boolean;
|
|
219
|
+
/** Error message to display */
|
|
220
|
+
error?: string | null;
|
|
221
|
+
/** Compact layout */
|
|
222
|
+
compact?: boolean;
|
|
223
|
+
/** Show all metrics or just primary ones */
|
|
224
|
+
showAll?: boolean;
|
|
225
|
+
/** Custom CSS class */
|
|
226
|
+
className?: string;
|
|
227
|
+
/** Theme variant */
|
|
228
|
+
theme?: 'light' | 'dark';
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* VitalsCard - Display component for vital sign results
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```tsx
|
|
235
|
+
* <VitalsCard
|
|
236
|
+
* heartRate={72}
|
|
237
|
+
* spo2={98}
|
|
238
|
+
* stressIndex={25}
|
|
239
|
+
* hrvSdnn={45}
|
|
240
|
+
* />
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
declare const VitalsCard: React$1.FC<VitalsCardProps>;
|
|
244
|
+
/**
|
|
245
|
+
* Helper component to create VitalsCard from full VitalsResult object
|
|
246
|
+
*/
|
|
247
|
+
declare const VitalsCardFromResult: React$1.FC<{
|
|
248
|
+
result: VitalsResult | null;
|
|
249
|
+
loading?: boolean;
|
|
250
|
+
error?: string | null;
|
|
251
|
+
showAll?: boolean;
|
|
252
|
+
compact?: boolean;
|
|
253
|
+
className?: string;
|
|
254
|
+
theme?: 'light' | 'dark';
|
|
255
|
+
}>;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Configuration for PulseClient
|
|
259
|
+
*/
|
|
260
|
+
interface PulseClientConfig {
|
|
261
|
+
/** Your PulseAI API key (starts with pk_live_ or pk_test_) */
|
|
262
|
+
apiKey: string;
|
|
263
|
+
/** API base URL (optional - defaults to VITE_API_URL env var or localhost) */
|
|
264
|
+
baseUrl?: string;
|
|
265
|
+
/** Request timeout in milliseconds (default: 60000) */
|
|
266
|
+
timeout?: number;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Options for medical vitals analysis
|
|
270
|
+
*/
|
|
271
|
+
interface AnalyzeOptions {
|
|
272
|
+
/** Video blob to analyze (webm or mp4) */
|
|
273
|
+
video: Blob;
|
|
274
|
+
/** User's age for calibration */
|
|
275
|
+
age?: number;
|
|
276
|
+
/** User's biological sex */
|
|
277
|
+
sex?: 'male' | 'female';
|
|
278
|
+
/** User's weight in kg (for BMI calculation) */
|
|
279
|
+
weight?: number;
|
|
280
|
+
/** User's height in cm (for BMI calculation) */
|
|
281
|
+
height?: number;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Options for beauty skin analysis
|
|
285
|
+
*/
|
|
286
|
+
interface BeautyAnalyzeOptions {
|
|
287
|
+
/** Video blob to analyze */
|
|
288
|
+
video: Blob;
|
|
289
|
+
/** User's age */
|
|
290
|
+
age?: number;
|
|
291
|
+
/** User's gender */
|
|
292
|
+
gender?: 'male' | 'female';
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* PulseAI API Client
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```typescript
|
|
299
|
+
* const client = new PulseClient({ apiKey: 'pk_live_...' });
|
|
300
|
+
* const vitals = await client.analyze({ video: videoBlob });
|
|
301
|
+
* console.log(vitals.heart_rate);
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
declare class PulseClient {
|
|
305
|
+
private apiKey;
|
|
306
|
+
private baseUrl;
|
|
307
|
+
private timeout;
|
|
308
|
+
constructor(config: PulseClientConfig);
|
|
309
|
+
/**
|
|
310
|
+
* Analyze video for medical vital signs
|
|
311
|
+
* Returns heart rate, HRV, SpO2, stress index, and more.
|
|
312
|
+
*/
|
|
313
|
+
analyze(options: AnalyzeOptions): Promise<VitalsResult>;
|
|
314
|
+
/**
|
|
315
|
+
* Analyze video for beauty/skin metrics
|
|
316
|
+
* Returns skin age, texture, hydration, symmetry, and recommendations.
|
|
317
|
+
*/
|
|
318
|
+
analyzeBeauty(options: BeautyAnalyzeOptions): Promise<BeautyResult>;
|
|
319
|
+
/**
|
|
320
|
+
* Check API health status
|
|
321
|
+
*/
|
|
322
|
+
health(): Promise<{
|
|
323
|
+
status: string;
|
|
324
|
+
service: string;
|
|
325
|
+
}>;
|
|
326
|
+
/**
|
|
327
|
+
* Internal request handler with timeout and error handling
|
|
328
|
+
*/
|
|
329
|
+
private request;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
interface UseCameraOptions {
|
|
333
|
+
width?: number;
|
|
334
|
+
height?: number;
|
|
335
|
+
facingMode?: 'user' | 'environment';
|
|
336
|
+
autoStart?: boolean;
|
|
337
|
+
}
|
|
338
|
+
interface UseCameraReturn {
|
|
339
|
+
videoRef: React.RefObject<HTMLVideoElement | null>;
|
|
340
|
+
stream: MediaStream | null;
|
|
341
|
+
isActive: boolean;
|
|
342
|
+
error: string | null;
|
|
343
|
+
start: () => Promise<void>;
|
|
344
|
+
stop: () => void;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Hook for managing camera stream.
|
|
348
|
+
* Handles permissions and stream lifecycle.
|
|
349
|
+
*/
|
|
350
|
+
declare function useCamera(options?: UseCameraOptions): UseCameraReturn;
|
|
351
|
+
|
|
352
|
+
interface FaceDetectionResult {
|
|
353
|
+
detected: boolean;
|
|
354
|
+
landmarks: any[] | null;
|
|
355
|
+
qualityMessage: string;
|
|
356
|
+
isQualityGood: boolean;
|
|
357
|
+
brightness: number;
|
|
358
|
+
}
|
|
359
|
+
interface UseFaceDetectionOptions {
|
|
360
|
+
enabled?: boolean;
|
|
361
|
+
/** Canvas element for drawing mesh overlay */
|
|
362
|
+
meshCanvas?: HTMLCanvasElement | null;
|
|
363
|
+
/** Enable mesh drawing (default: false) */
|
|
364
|
+
drawMesh?: boolean;
|
|
365
|
+
}
|
|
366
|
+
interface UseFaceDetectionReturn extends FaceDetectionResult {
|
|
367
|
+
isLoading: boolean;
|
|
368
|
+
latestLandmarks: React.MutableRefObject<any[] | null>;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Hook for face detection using MediaPipe FaceLandmarker.
|
|
372
|
+
* Provides real-time face tracking and quality assessment.
|
|
373
|
+
*/
|
|
374
|
+
declare function useFaceDetection(videoElement: HTMLVideoElement | null, options?: UseFaceDetectionOptions): UseFaceDetectionReturn;
|
|
375
|
+
|
|
376
|
+
interface UseRecordingOptions {
|
|
377
|
+
duration?: number;
|
|
378
|
+
mimeType?: string;
|
|
379
|
+
onComplete?: (blob: Blob) => void;
|
|
380
|
+
}
|
|
381
|
+
interface UseRecordingReturn {
|
|
382
|
+
isRecording: boolean;
|
|
383
|
+
timeLeft: number;
|
|
384
|
+
blob: Blob | null;
|
|
385
|
+
start: () => void;
|
|
386
|
+
stop: () => void;
|
|
387
|
+
reset: () => void;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Hook for managing video recording from a MediaStream.
|
|
391
|
+
* Handles countdown timer and blob generation.
|
|
392
|
+
*/
|
|
393
|
+
declare function useRecording(stream: MediaStream | null, options?: UseRecordingOptions): UseRecordingReturn;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* PulseAI React SDK
|
|
397
|
+
*
|
|
398
|
+
* Measure vital signs from any camera using remote photoplethysmography (rPPG).
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```tsx
|
|
402
|
+
* import { PulseScanner, VitalsCard, PulseClient } from '@pulseai/react';
|
|
403
|
+
* import '@pulseai/react/styles.css';
|
|
404
|
+
*
|
|
405
|
+
* function App() {
|
|
406
|
+
* const [vitals, setVitals] = useState(null);
|
|
407
|
+
*
|
|
408
|
+
* return (
|
|
409
|
+
* <>
|
|
410
|
+
* <PulseScanner
|
|
411
|
+
* apiKey="pk_live_..."
|
|
412
|
+
* duration={10}
|
|
413
|
+
* onResult={setVitals}
|
|
414
|
+
* />
|
|
415
|
+
* {vitals && (
|
|
416
|
+
* <VitalsCard
|
|
417
|
+
* heartRate={vitals.heart_rate}
|
|
418
|
+
* spo2={vitals.spo2}
|
|
419
|
+
* stressIndex={vitals.stress_index}
|
|
420
|
+
* />
|
|
421
|
+
* )}
|
|
422
|
+
* </>
|
|
423
|
+
* );
|
|
424
|
+
* }
|
|
425
|
+
* ```
|
|
426
|
+
*
|
|
427
|
+
* @packageDocumentation
|
|
428
|
+
*/
|
|
429
|
+
|
|
430
|
+
declare const VERSION = "1.0.0";
|
|
431
|
+
|
|
432
|
+
export { type APIError, type APIResponse, type AnalyzeOptions, type ArrhythmiaResult, type BMIEstimate, type BeautyAnalyzeOptions, type BeautyGeometry, type BeautyPhysiology, type BeautyRecommendations, type BeautyResult, type BeautySummary, type BeautySurface, type BloodPressure, type CompositeScores, type FaceDetectionResult, type MentalWellness, PulseClient, type PulseClientConfig, PulseScanner, type PulseScannerProps, type ScannerStatus, type UseCameraOptions, type UseCameraReturn, type UseFaceDetectionOptions, type UseFaceDetectionReturn, type UseRecordingOptions, type UseRecordingReturn, VERSION, type VisualAnalysis, VitalsCard, VitalsCardFromResult, type VitalsCardProps, type VitalsResult, useCamera, useFaceDetection, useRecording };
|