screenwright 0.1.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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/assets/click-ripple.svg +3 -0
  3. package/assets/cursor-default.svg +10 -0
  4. package/assets/cursor-pointer.svg +40 -0
  5. package/dist/bin/screenwright.d.ts +3 -0
  6. package/dist/bin/screenwright.d.ts.map +1 -0
  7. package/dist/bin/screenwright.js +18 -0
  8. package/dist/bin/screenwright.js.map +1 -0
  9. package/dist/src/commands/compose.d.ts +3 -0
  10. package/dist/src/commands/compose.d.ts.map +1 -0
  11. package/dist/src/commands/compose.js +154 -0
  12. package/dist/src/commands/compose.js.map +1 -0
  13. package/dist/src/commands/generate.d.ts +3 -0
  14. package/dist/src/commands/generate.d.ts.map +1 -0
  15. package/dist/src/commands/generate.js +70 -0
  16. package/dist/src/commands/generate.js.map +1 -0
  17. package/dist/src/commands/init.d.ts +3 -0
  18. package/dist/src/commands/init.d.ts.map +1 -0
  19. package/dist/src/commands/init.js +49 -0
  20. package/dist/src/commands/init.js.map +1 -0
  21. package/dist/src/commands/preview.d.ts +3 -0
  22. package/dist/src/commands/preview.d.ts.map +1 -0
  23. package/dist/src/commands/preview.js +62 -0
  24. package/dist/src/commands/preview.js.map +1 -0
  25. package/dist/src/composition/CursorOverlay.d.ts +11 -0
  26. package/dist/src/composition/CursorOverlay.d.ts.map +1 -0
  27. package/dist/src/composition/CursorOverlay.js +29 -0
  28. package/dist/src/composition/CursorOverlay.js.map +1 -0
  29. package/dist/src/composition/DemoVideo.d.ts +8 -0
  30. package/dist/src/composition/DemoVideo.d.ts.map +1 -0
  31. package/dist/src/composition/DemoVideo.js +18 -0
  32. package/dist/src/composition/DemoVideo.js.map +1 -0
  33. package/dist/src/composition/NarrationTrack.d.ts +9 -0
  34. package/dist/src/composition/NarrationTrack.d.ts.map +1 -0
  35. package/dist/src/composition/NarrationTrack.js +8 -0
  36. package/dist/src/composition/NarrationTrack.js.map +1 -0
  37. package/dist/src/composition/cursor-path.d.ts +31 -0
  38. package/dist/src/composition/cursor-path.d.ts.map +1 -0
  39. package/dist/src/composition/cursor-path.js +78 -0
  40. package/dist/src/composition/cursor-path.js.map +1 -0
  41. package/dist/src/composition/remotion-root.d.ts +3 -0
  42. package/dist/src/composition/remotion-root.d.ts.map +1 -0
  43. package/dist/src/composition/remotion-root.js +34 -0
  44. package/dist/src/composition/remotion-root.js.map +1 -0
  45. package/dist/src/composition/render.d.ts +8 -0
  46. package/dist/src/composition/render.d.ts.map +1 -0
  47. package/dist/src/composition/render.js +24 -0
  48. package/dist/src/composition/render.js.map +1 -0
  49. package/dist/src/config/config-schema.d.ts +40 -0
  50. package/dist/src/config/config-schema.d.ts.map +1 -0
  51. package/dist/src/config/config-schema.js +13 -0
  52. package/dist/src/config/config-schema.js.map +1 -0
  53. package/dist/src/config/defaults.d.ts +4 -0
  54. package/dist/src/config/defaults.d.ts.map +1 -0
  55. package/dist/src/config/defaults.js +17 -0
  56. package/dist/src/config/defaults.js.map +1 -0
  57. package/dist/src/generator/prompts.d.ts +3 -0
  58. package/dist/src/generator/prompts.d.ts.map +1 -0
  59. package/dist/src/generator/prompts.js +125 -0
  60. package/dist/src/generator/prompts.js.map +1 -0
  61. package/dist/src/generator/scenario-generator.d.ts +46 -0
  62. package/dist/src/generator/scenario-generator.d.ts.map +1 -0
  63. package/dist/src/generator/scenario-generator.js +86 -0
  64. package/dist/src/generator/scenario-generator.js.map +1 -0
  65. package/dist/src/index.d.ts +7 -0
  66. package/dist/src/index.d.ts.map +1 -0
  67. package/dist/src/index.js +2 -0
  68. package/dist/src/index.js.map +1 -0
  69. package/dist/src/runtime/action-helpers.d.ts +19 -0
  70. package/dist/src/runtime/action-helpers.d.ts.map +1 -0
  71. package/dist/src/runtime/action-helpers.js +138 -0
  72. package/dist/src/runtime/action-helpers.js.map +1 -0
  73. package/dist/src/runtime/instrumented-page.d.ts +21 -0
  74. package/dist/src/runtime/instrumented-page.d.ts.map +1 -0
  75. package/dist/src/runtime/instrumented-page.js +48 -0
  76. package/dist/src/runtime/instrumented-page.js.map +1 -0
  77. package/dist/src/runtime/timeline-collector.d.ts +20 -0
  78. package/dist/src/runtime/timeline-collector.d.ts.map +1 -0
  79. package/dist/src/runtime/timeline-collector.js +40 -0
  80. package/dist/src/runtime/timeline-collector.js.map +1 -0
  81. package/dist/src/timeline/schema.d.ts +297 -0
  82. package/dist/src/timeline/schema.d.ts.map +1 -0
  83. package/dist/src/timeline/schema.js +72 -0
  84. package/dist/src/timeline/schema.js.map +1 -0
  85. package/dist/src/timeline/types.d.ts +67 -0
  86. package/dist/src/timeline/types.d.ts.map +1 -0
  87. package/dist/src/timeline/types.js +2 -0
  88. package/dist/src/timeline/types.js.map +1 -0
  89. package/dist/src/version.d.ts +2 -0
  90. package/dist/src/version.d.ts.map +1 -0
  91. package/dist/src/version.js +2 -0
  92. package/dist/src/version.js.map +1 -0
  93. package/dist/src/voiceover/narration-timing.d.ts +12 -0
  94. package/dist/src/voiceover/narration-timing.d.ts.map +1 -0
  95. package/dist/src/voiceover/narration-timing.js +25 -0
  96. package/dist/src/voiceover/narration-timing.js.map +1 -0
  97. package/dist/src/voiceover/piper-engine.d.ts +6 -0
  98. package/dist/src/voiceover/piper-engine.d.ts.map +1 -0
  99. package/dist/src/voiceover/piper-engine.js +48 -0
  100. package/dist/src/voiceover/piper-engine.js.map +1 -0
  101. package/dist/src/voiceover/voice-models.d.ts +18 -0
  102. package/dist/src/voiceover/voice-models.d.ts.map +1 -0
  103. package/dist/src/voiceover/voice-models.js +123 -0
  104. package/dist/src/voiceover/voice-models.js.map +1 -0
  105. package/dist/tsconfig.tsbuildinfo +1 -0
  106. package/package.json +69 -0
@@ -0,0 +1,72 @@
1
+ import { z } from 'zod';
2
+ const sceneEventSchema = z.object({
3
+ type: z.literal('scene'),
4
+ id: z.string(),
5
+ timestampMs: z.number().nonnegative(),
6
+ title: z.string(),
7
+ description: z.string().optional(),
8
+ });
9
+ const actionEventSchema = z.object({
10
+ type: z.literal('action'),
11
+ id: z.string(),
12
+ timestampMs: z.number().nonnegative(),
13
+ action: z.enum(['click', 'fill', 'hover', 'select', 'press', 'navigate']),
14
+ selector: z.string(),
15
+ value: z.string().optional(),
16
+ durationMs: z.number().nonnegative(),
17
+ boundingBox: z.object({
18
+ x: z.number(),
19
+ y: z.number(),
20
+ width: z.number().positive(),
21
+ height: z.number().positive(),
22
+ }).nullable(),
23
+ });
24
+ const cursorTargetEventSchema = z.object({
25
+ type: z.literal('cursor_target'),
26
+ id: z.string(),
27
+ timestampMs: z.number().nonnegative(),
28
+ fromX: z.number(),
29
+ fromY: z.number(),
30
+ toX: z.number(),
31
+ toY: z.number(),
32
+ moveDurationMs: z.number().positive(),
33
+ easing: z.literal('bezier'),
34
+ });
35
+ const narrationEventSchema = z.object({
36
+ type: z.literal('narration'),
37
+ id: z.string(),
38
+ timestampMs: z.number().nonnegative(),
39
+ text: z.string().min(1),
40
+ audioDurationMs: z.number().positive().optional(),
41
+ audioFile: z.string().optional(),
42
+ });
43
+ const waitEventSchema = z.object({
44
+ type: z.literal('wait'),
45
+ id: z.string(),
46
+ timestampMs: z.number().nonnegative(),
47
+ durationMs: z.number().positive(),
48
+ reason: z.enum(['pacing', 'narration_sync', 'page_load']),
49
+ });
50
+ const timelineEventSchema = z.discriminatedUnion('type', [
51
+ sceneEventSchema,
52
+ actionEventSchema,
53
+ cursorTargetEventSchema,
54
+ narrationEventSchema,
55
+ waitEventSchema,
56
+ ]);
57
+ export const timelineSchema = z.object({
58
+ version: z.literal(1),
59
+ metadata: z.object({
60
+ testFile: z.string(),
61
+ scenarioFile: z.string(),
62
+ recordedAt: z.string().datetime(),
63
+ viewport: z.object({
64
+ width: z.number().int().positive(),
65
+ height: z.number().int().positive(),
66
+ }),
67
+ videoDurationMs: z.number().nonnegative(),
68
+ videoFile: z.string(),
69
+ }),
70
+ events: z.array(timelineEventSchema),
71
+ });
72
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/timeline/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ export interface Timeline {
2
+ version: 1;
3
+ metadata: TimelineMetadata;
4
+ events: TimelineEvent[];
5
+ }
6
+ export interface TimelineMetadata {
7
+ testFile: string;
8
+ scenarioFile: string;
9
+ recordedAt: string;
10
+ viewport: {
11
+ width: number;
12
+ height: number;
13
+ };
14
+ videoDurationMs: number;
15
+ videoFile: string;
16
+ }
17
+ export type TimelineEvent = SceneEvent | ActionEvent | CursorTargetEvent | NarrationEvent | WaitEvent;
18
+ export interface SceneEvent {
19
+ type: 'scene';
20
+ id: string;
21
+ timestampMs: number;
22
+ title: string;
23
+ description?: string;
24
+ }
25
+ export type ActionType = 'click' | 'fill' | 'hover' | 'select' | 'press' | 'navigate';
26
+ export interface ActionEvent {
27
+ type: 'action';
28
+ id: string;
29
+ timestampMs: number;
30
+ action: ActionType;
31
+ selector: string;
32
+ value?: string;
33
+ durationMs: number;
34
+ boundingBox: {
35
+ x: number;
36
+ y: number;
37
+ width: number;
38
+ height: number;
39
+ } | null;
40
+ }
41
+ export interface CursorTargetEvent {
42
+ type: 'cursor_target';
43
+ id: string;
44
+ timestampMs: number;
45
+ fromX: number;
46
+ fromY: number;
47
+ toX: number;
48
+ toY: number;
49
+ moveDurationMs: number;
50
+ easing: 'bezier';
51
+ }
52
+ export interface NarrationEvent {
53
+ type: 'narration';
54
+ id: string;
55
+ timestampMs: number;
56
+ text: string;
57
+ audioDurationMs?: number;
58
+ audioFile?: string;
59
+ }
60
+ export interface WaitEvent {
61
+ type: 'wait';
62
+ id: string;
63
+ timestampMs: number;
64
+ durationMs: number;
65
+ reason: 'pacing' | 'narration_sync' | 'page_load';
66
+ }
67
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/timeline/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,SAAS,CAAC;AAEd,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7E;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,GAAG,gBAAgB,GAAG,WAAW,CAAC;CACnD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/timeline/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare const VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Timeline } from '../timeline/types.js';
2
+ export interface NarrationOptions {
3
+ modelPath?: string;
4
+ tempDir: string;
5
+ }
6
+ /**
7
+ * Generate voiceover WAV files for all narration events in a timeline.
8
+ * Updates each narration event with the audioFile path and actual duration.
9
+ * Returns a new timeline with updated narration events.
10
+ */
11
+ export declare function generateNarration(timeline: Timeline, opts: NarrationOptions): Promise<Timeline>;
12
+ //# sourceMappingURL=narration-timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-timing.d.ts","sourceRoot":"","sources":["../../../src/voiceover/narration-timing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,sBAAsB,CAAC;AAGrE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,QAAQ,CAAC,CAoBnB"}
@@ -0,0 +1,25 @@
1
+ import { join } from 'node:path';
2
+ import { synthesize } from './piper-engine.js';
3
+ /**
4
+ * Generate voiceover WAV files for all narration events in a timeline.
5
+ * Updates each narration event with the audioFile path and actual duration.
6
+ * Returns a new timeline with updated narration events.
7
+ */
8
+ export async function generateNarration(timeline, opts) {
9
+ const events = [...timeline.events];
10
+ for (let i = 0; i < events.length; i++) {
11
+ const event = events[i];
12
+ if (event.type !== 'narration')
13
+ continue;
14
+ const narration = event;
15
+ const outputPath = join(opts.tempDir, `narration-${narration.id}.wav`);
16
+ const result = await synthesize(narration.text, outputPath, opts.modelPath);
17
+ events[i] = {
18
+ ...narration,
19
+ audioFile: result.wavPath,
20
+ audioDurationMs: result.durationMs,
21
+ };
22
+ }
23
+ return { ...timeline, events };
24
+ }
25
+ //# sourceMappingURL=narration-timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-timing.js","sourceRoot":"","sources":["../../../src/voiceover/narration-timing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAO/C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAkB,EAClB,IAAsB;IAEtB,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QAEzC,MAAM,SAAS,GAAG,KAAuB,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;QAEvE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE5E,MAAM,CAAC,CAAC,CAAC,GAAG;YACV,GAAG,SAAS;YACZ,SAAS,EAAE,MAAM,CAAC,OAAO;YACzB,eAAe,EAAE,MAAM,CAAC,UAAU;SACnC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface SynthesizeResult {
2
+ wavPath: string;
3
+ durationMs: number;
4
+ }
5
+ export declare function synthesize(text: string, outputPath: string, modelPath?: string, piperBinOverride?: string): Promise<SynthesizeResult>;
6
+ //# sourceMappingURL=piper-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piper-engine.d.ts","sourceRoot":"","sources":["../../../src/voiceover/piper-engine.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
@@ -0,0 +1,48 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { getVoiceModelPath, downloadPiper } from './voice-models.js';
5
+ const execFileAsync = promisify(execFile);
6
+ export async function synthesize(text, outputPath, modelPath, piperBinOverride) {
7
+ const piperBin = piperBinOverride ?? await downloadPiper();
8
+ const model = modelPath ?? getVoiceModelPath('en_US-amy-medium');
9
+ return new Promise((resolve, reject) => {
10
+ const proc = spawn(piperBin, [
11
+ '--model', model,
12
+ '--output_file', outputPath,
13
+ ]);
14
+ let stderr = '';
15
+ proc.stderr.on('data', (data) => { stderr += data; });
16
+ proc.on('close', async (code) => {
17
+ if (code !== 0) {
18
+ reject(new Error(`Piper exited with code ${code}: ${stderr}`));
19
+ return;
20
+ }
21
+ const durationMs = await measureDuration(outputPath);
22
+ resolve({ wavPath: outputPath, durationMs });
23
+ });
24
+ proc.stdin.write(text);
25
+ proc.stdin.end();
26
+ });
27
+ }
28
+ async function measureDuration(wavPath) {
29
+ try {
30
+ const { stdout } = await execFileAsync('ffprobe', [
31
+ '-v', 'quiet',
32
+ '-show_entries', 'format=duration',
33
+ '-of', 'csv=p=0',
34
+ wavPath,
35
+ ]);
36
+ return Math.round(parseFloat(stdout.trim()) * 1000);
37
+ }
38
+ catch {
39
+ // Fallback: estimate from file size (16kHz 16-bit mono WAV)
40
+ const { stat } = await import('node:fs/promises');
41
+ const stats = await stat(wavPath);
42
+ const dataBytes = stats.size - 44; // WAV header
43
+ const samplesPerSec = 22050;
44
+ const bytesPerSample = 2;
45
+ return Math.round((dataBytes / (samplesPerSec * bytesPerSample)) * 1000);
46
+ }
47
+ }
48
+ //# sourceMappingURL=piper-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piper-engine.js","sourceRoot":"","sources":["../../../src/voiceover/piper-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAO1C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,UAAkB,EAClB,SAAkB,EAClB,gBAAyB;IAEzB,MAAM,QAAQ,GAAG,gBAAgB,IAAI,MAAM,aAAa,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,SAAS,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IAEjE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE;YAC3B,SAAS,EAAE,KAAK;YAChB,eAAe,EAAE,UAAU;SAC5B,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC9B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;YACrD,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE;YAChD,IAAI,EAAE,OAAO;YACb,eAAe,EAAE,iBAAiB;YAClC,KAAK,EAAE,SAAS;YAChB,OAAO;SACR,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;QAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,aAAa;QAChD,MAAM,aAAa,GAAG,KAAK,CAAC;QAC5B,MAAM,cAAc,GAAG,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,aAAa,GAAG,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface VoiceModel {
2
+ name: string;
3
+ onnxUrl: string;
4
+ configUrl: string;
5
+ }
6
+ export declare const DEFAULT_VOICE: VoiceModel;
7
+ export declare function getScreenwrightDir(): string;
8
+ export declare function getPiperBinPath(): string;
9
+ export declare function getVoiceModelPath(modelName: string): string;
10
+ export declare function getVoiceConfigPath(modelName: string): string;
11
+ export declare function exists(path: string): Promise<boolean>;
12
+ export declare function downloadPiper(): Promise<string>;
13
+ export declare function downloadVoiceModel(model?: VoiceModel): Promise<string>;
14
+ export declare function ensureDependencies(modelName?: string): Promise<{
15
+ piperBin: string;
16
+ modelPath: string;
17
+ }>;
18
+ //# sourceMappingURL=voice-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-models.d.ts","sourceRoot":"","sources":["../../../src/voiceover/voice-models.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,UAI3B,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO3D;AAmED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CASrD;AAED,wBAAsB,kBAAkB,CAAC,KAAK,GAAE,UAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB3F;AAED,wBAAsB,kBAAkB,CAAC,SAAS,SAAqB,GAAG,OAAO,CAAC;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CASD"}
@@ -0,0 +1,123 @@
1
+ import { mkdir, access } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { execFile } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ const execFileAsync = promisify(execFile);
7
+ const PIPER_GITHUB = 'https://github.com/rhasspy/piper/releases/download';
8
+ const PIPER_VERSION = '2023.11.14-2';
9
+ const VOICE_BASE_URL = 'https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0';
10
+ export const DEFAULT_VOICE = {
11
+ name: 'en_US-amy-medium',
12
+ onnxUrl: `${VOICE_BASE_URL}/en/en_US/amy/medium/en_US-amy-medium.onnx`,
13
+ configUrl: `${VOICE_BASE_URL}/en/en_US/amy/medium/en_US-amy-medium.onnx.json`,
14
+ };
15
+ export function getScreenwrightDir() {
16
+ return join(homedir(), '.screenwright');
17
+ }
18
+ export function getPiperBinPath() {
19
+ return join(getScreenwrightDir(), 'bin', 'piper');
20
+ }
21
+ export function getVoiceModelPath(modelName) {
22
+ return join(getScreenwrightDir(), 'voices', `${modelName}.onnx`);
23
+ }
24
+ export function getVoiceConfigPath(modelName) {
25
+ return join(getScreenwrightDir(), 'voices', `${modelName}.onnx.json`);
26
+ }
27
+ export async function exists(path) {
28
+ try {
29
+ await access(path);
30
+ return true;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ // The official Piper aarch64 macOS release is mispackaged (ships x86_64 binary).
37
+ // On macOS ARM64, use the Python piper-tts package which has native onnxruntime.
38
+ function needsPythonFallback() {
39
+ return process.platform === 'darwin' && process.arch === 'arm64';
40
+ }
41
+ function getNativePiperUrl() {
42
+ const platform = process.platform;
43
+ const arch = process.arch;
44
+ if (platform === 'linux') {
45
+ return `${PIPER_GITHUB}/${PIPER_VERSION}/piper_linux_${arch === 'arm64' ? 'aarch64' : 'x86_64'}.tar.gz`;
46
+ }
47
+ if (platform === 'darwin') {
48
+ return `${PIPER_GITHUB}/${PIPER_VERSION}/piper_macos_x64.tar.gz`;
49
+ }
50
+ throw new Error(`Unsupported platform: ${platform}`);
51
+ }
52
+ async function findPythonPiper() {
53
+ for (const cmd of ['piper', `${homedir()}/Library/Python/3.9/bin/piper`]) {
54
+ try {
55
+ await execFileAsync(cmd, ['--help']);
56
+ return cmd;
57
+ }
58
+ catch {
59
+ // not found
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ async function installPythonPiper() {
65
+ const existing = await findPythonPiper();
66
+ if (existing)
67
+ return existing;
68
+ console.log('Installing piper-tts via pip3...');
69
+ await execFileAsync('pip3', ['install', 'piper-tts', 'pathvalidate']);
70
+ const bin = await findPythonPiper();
71
+ if (!bin) {
72
+ throw new Error('pip3 install piper-tts succeeded but piper not found on PATH. ' +
73
+ 'Add your pip bin directory to PATH.');
74
+ }
75
+ return bin;
76
+ }
77
+ async function downloadNativePiper() {
78
+ const binPath = getPiperBinPath();
79
+ if (await exists(binPath))
80
+ return binPath;
81
+ const binDir = join(getScreenwrightDir(), 'bin');
82
+ await mkdir(binDir, { recursive: true });
83
+ const url = getNativePiperUrl();
84
+ console.log(`Downloading Piper from ${url}...`);
85
+ await execFileAsync('bash', ['-c', `curl -sL "${url}" | tar xz -C "${binDir}" --strip-components=1`]);
86
+ await execFileAsync('chmod', ['+x', binPath]);
87
+ console.log('Piper installed successfully.');
88
+ return binPath;
89
+ }
90
+ export async function downloadPiper() {
91
+ // If piper is already on PATH (e.g. pip install in CI), use it
92
+ const existing = await findPythonPiper();
93
+ if (existing)
94
+ return existing;
95
+ if (needsPythonFallback()) {
96
+ return installPythonPiper();
97
+ }
98
+ return downloadNativePiper();
99
+ }
100
+ export async function downloadVoiceModel(model = DEFAULT_VOICE) {
101
+ const modelPath = getVoiceModelPath(model.name);
102
+ const configPath = getVoiceConfigPath(model.name);
103
+ if (await exists(modelPath) && await exists(configPath))
104
+ return modelPath;
105
+ const voicesDir = join(getScreenwrightDir(), 'voices');
106
+ await mkdir(voicesDir, { recursive: true });
107
+ console.log(`Downloading voice model: ${model.name}...`);
108
+ await execFileAsync('curl', ['-sL', '-o', modelPath, model.onnxUrl]);
109
+ await execFileAsync('curl', ['-sL', '-o', configPath, model.configUrl]);
110
+ console.log('Voice model downloaded.');
111
+ return modelPath;
112
+ }
113
+ export async function ensureDependencies(modelName = 'en_US-amy-medium') {
114
+ const piperBin = await downloadPiper();
115
+ const model = modelName === DEFAULT_VOICE.name ? DEFAULT_VOICE : {
116
+ name: modelName,
117
+ onnxUrl: `${VOICE_BASE_URL}/en/en_US/${modelName.split('-')[1]}/${modelName.split('-')[2]}/${modelName}.onnx`,
118
+ configUrl: `${VOICE_BASE_URL}/en/en_US/${modelName.split('-')[1]}/${modelName.split('-')[2]}/${modelName}.onnx.json`,
119
+ };
120
+ const modelPath = await downloadVoiceModel(model);
121
+ return { piperBin, modelPath };
122
+ }
123
+ //# sourceMappingURL=voice-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-models.js","sourceRoot":"","sources":["../../../src/voiceover/voice-models.ts"],"names":[],"mappings":"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"}