@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/dist/index.d.ts
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 };
|