@lssm-tech/lib.voice 1.7.29 → 3.0.2
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 +8 -8
- package/package.json +234 -321
- package/dist/audio/audio-concatenator.d.ts +0 -15
- package/dist/audio/audio-concatenator.js +0 -2
- package/dist/audio/duration-estimator.d.ts +0 -31
- package/dist/audio/duration-estimator.js +0 -2
- package/dist/audio/format-converter.d.ts +0 -17
- package/dist/audio/format-converter.js +0 -2
- package/dist/audio/index.d.ts +0 -4
- package/dist/audio/index.js +0 -2
- package/dist/audio/silence-generator.d.ts +0 -16
- package/dist/audio/silence-generator.js +0 -2
- package/dist/browser/audio/audio-concatenator.js +0 -1
- package/dist/browser/audio/duration-estimator.js +0 -1
- package/dist/browser/audio/format-converter.js +0 -1
- package/dist/browser/audio/index.js +0 -1
- package/dist/browser/audio/silence-generator.js +0 -1
- package/dist/browser/conversational/index.js +0 -2
- package/dist/browser/conversational/response-orchestrator.js +0 -1
- package/dist/browser/conversational/transcript-builder.js +0 -2
- package/dist/browser/conversational/turn-detector.js +0 -1
- package/dist/browser/conversational/types.js +0 -0
- package/dist/browser/conversational/voice-session-manager.js +0 -2
- package/dist/browser/docs/conversational.docblock.js +0 -1
- package/dist/browser/docs/stt.docblock.js +0 -1
- package/dist/browser/docs/sync.docblock.js +0 -1
- package/dist/browser/docs/tts.docblock.js +0 -1
- package/dist/browser/docs/voice.docblock.js +0 -1
- package/dist/browser/i18n/catalogs/en.js +0 -3
- package/dist/browser/i18n/catalogs/es.js +0 -3
- package/dist/browser/i18n/catalogs/fr.js +0 -3
- package/dist/browser/i18n/catalogs/index.js +0 -7
- package/dist/browser/i18n/index.js +0 -7
- package/dist/browser/i18n/keys.js +0 -1
- package/dist/browser/i18n/locale.js +0 -1
- package/dist/browser/i18n/messages.js +0 -7
- package/dist/browser/index.js +0 -13
- package/dist/browser/stt/diarization-mapper.js +0 -1
- package/dist/browser/stt/index.js +0 -11
- package/dist/browser/stt/segment-splitter.js +0 -1
- package/dist/browser/stt/subtitle-formatter.js +0 -11
- package/dist/browser/stt/transcriber.js +0 -11
- package/dist/browser/stt/types.js +0 -0
- package/dist/browser/sync/duration-negotiator.js +0 -1
- package/dist/browser/sync/index.js +0 -1
- package/dist/browser/sync/scene-adapter.js +0 -1
- package/dist/browser/sync/timing-calculator.js +0 -1
- package/dist/browser/tts/audio-assembler.js +0 -1
- package/dist/browser/tts/emphasis-planner.js +0 -2
- package/dist/browser/tts/index.js +0 -2
- package/dist/browser/tts/pace-analyzer.js +0 -1
- package/dist/browser/tts/segment-synthesizer.js +0 -1
- package/dist/browser/tts/types.js +0 -0
- package/dist/browser/tts/voice-synthesizer.js +0 -2
- package/dist/browser/types.js +0 -0
- package/dist/browser/voice.feature.js +0 -1
- package/dist/conversational/index.d.ts +0 -5
- package/dist/conversational/index.js +0 -3
- package/dist/conversational/response-orchestrator.d.ts +0 -37
- package/dist/conversational/response-orchestrator.js +0 -2
- package/dist/conversational/transcript-builder.d.ts +0 -25
- package/dist/conversational/transcript-builder.js +0 -3
- package/dist/conversational/turn-detector.d.ts +0 -31
- package/dist/conversational/turn-detector.js +0 -2
- package/dist/conversational/types.d.ts +0 -60
- package/dist/conversational/types.js +0 -1
- package/dist/conversational/voice-session-manager.d.ts +0 -17
- package/dist/conversational/voice-session-manager.js +0 -3
- package/dist/docs/conversational.docblock.d.ts +0 -14
- package/dist/docs/conversational.docblock.js +0 -2
- package/dist/docs/stt.docblock.d.ts +0 -12
- package/dist/docs/stt.docblock.js +0 -2
- package/dist/docs/sync.docblock.d.ts +0 -12
- package/dist/docs/sync.docblock.js +0 -2
- package/dist/docs/tts.docblock.d.ts +0 -12
- package/dist/docs/tts.docblock.js +0 -2
- package/dist/docs/voice.docblock.d.ts +0 -22
- package/dist/docs/voice.docblock.js +0 -2
- package/dist/i18n/catalogs/en.d.ts +0 -6
- package/dist/i18n/catalogs/en.js +0 -4
- package/dist/i18n/catalogs/es.d.ts +0 -4
- package/dist/i18n/catalogs/es.js +0 -4
- package/dist/i18n/catalogs/fr.d.ts +0 -4
- package/dist/i18n/catalogs/fr.js +0 -4
- package/dist/i18n/catalogs/index.d.ts +0 -3
- package/dist/i18n/catalogs/index.js +0 -8
- package/dist/i18n/index.d.ts +0 -20
- package/dist/i18n/index.js +0 -8
- package/dist/i18n/keys.d.ts +0 -50
- package/dist/i18n/keys.js +0 -2
- package/dist/i18n/locale.d.ts +0 -6
- package/dist/i18n/locale.js +0 -2
- package/dist/i18n/messages.d.ts +0 -13
- package/dist/i18n/messages.js +0 -8
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -14
- package/dist/node/audio/audio-concatenator.js +0 -1
- package/dist/node/audio/duration-estimator.js +0 -1
- package/dist/node/audio/format-converter.js +0 -1
- package/dist/node/audio/index.js +0 -1
- package/dist/node/audio/silence-generator.js +0 -1
- package/dist/node/conversational/index.js +0 -2
- package/dist/node/conversational/response-orchestrator.js +0 -1
- package/dist/node/conversational/transcript-builder.js +0 -2
- package/dist/node/conversational/turn-detector.js +0 -1
- package/dist/node/conversational/types.js +0 -0
- package/dist/node/conversational/voice-session-manager.js +0 -2
- package/dist/node/docs/conversational.docblock.js +0 -1
- package/dist/node/docs/stt.docblock.js +0 -1
- package/dist/node/docs/sync.docblock.js +0 -1
- package/dist/node/docs/tts.docblock.js +0 -1
- package/dist/node/docs/voice.docblock.js +0 -1
- package/dist/node/i18n/catalogs/en.js +0 -3
- package/dist/node/i18n/catalogs/es.js +0 -3
- package/dist/node/i18n/catalogs/fr.js +0 -3
- package/dist/node/i18n/catalogs/index.js +0 -7
- package/dist/node/i18n/index.js +0 -7
- package/dist/node/i18n/keys.js +0 -1
- package/dist/node/i18n/locale.js +0 -1
- package/dist/node/i18n/messages.js +0 -7
- package/dist/node/index.js +0 -13
- package/dist/node/stt/diarization-mapper.js +0 -1
- package/dist/node/stt/index.js +0 -11
- package/dist/node/stt/segment-splitter.js +0 -1
- package/dist/node/stt/subtitle-formatter.js +0 -11
- package/dist/node/stt/transcriber.js +0 -11
- package/dist/node/stt/types.js +0 -0
- package/dist/node/sync/duration-negotiator.js +0 -1
- package/dist/node/sync/index.js +0 -1
- package/dist/node/sync/scene-adapter.js +0 -1
- package/dist/node/sync/timing-calculator.js +0 -1
- package/dist/node/tts/audio-assembler.js +0 -1
- package/dist/node/tts/emphasis-planner.js +0 -2
- package/dist/node/tts/index.js +0 -2
- package/dist/node/tts/pace-analyzer.js +0 -1
- package/dist/node/tts/segment-synthesizer.js +0 -1
- package/dist/node/tts/types.js +0 -0
- package/dist/node/tts/voice-synthesizer.js +0 -2
- package/dist/node/types.js +0 -0
- package/dist/node/voice.feature.js +0 -1
- package/dist/stt/diarization-mapper.d.ts +0 -19
- package/dist/stt/diarization-mapper.js +0 -2
- package/dist/stt/index.d.ts +0 -5
- package/dist/stt/index.js +0 -12
- package/dist/stt/segment-splitter.d.ts +0 -19
- package/dist/stt/segment-splitter.js +0 -2
- package/dist/stt/subtitle-formatter.d.ts +0 -19
- package/dist/stt/subtitle-formatter.js +0 -12
- package/dist/stt/transcriber.d.ts +0 -21
- package/dist/stt/transcriber.js +0 -12
- package/dist/stt/types.d.ts +0 -44
- package/dist/stt/types.js +0 -1
- package/dist/sync/duration-negotiator.d.ts +0 -37
- package/dist/sync/duration-negotiator.js +0 -2
- package/dist/sync/index.d.ts +0 -3
- package/dist/sync/index.js +0 -2
- package/dist/sync/scene-adapter.d.ts +0 -29
- package/dist/sync/scene-adapter.js +0 -2
- package/dist/sync/timing-calculator.d.ts +0 -21
- package/dist/sync/timing-calculator.js +0 -2
- package/dist/tts/audio-assembler.d.ts +0 -19
- package/dist/tts/audio-assembler.js +0 -2
- package/dist/tts/emphasis-planner.d.ts +0 -31
- package/dist/tts/emphasis-planner.js +0 -3
- package/dist/tts/index.d.ts +0 -6
- package/dist/tts/index.js +0 -3
- package/dist/tts/pace-analyzer.d.ts +0 -30
- package/dist/tts/pace-analyzer.js +0 -2
- package/dist/tts/segment-synthesizer.d.ts +0 -21
- package/dist/tts/segment-synthesizer.js +0 -2
- package/dist/tts/types.d.ts +0 -76
- package/dist/tts/types.js +0 -1
- package/dist/tts/voice-synthesizer.d.ts +0 -28
- package/dist/tts/voice-synthesizer.js +0 -3
- package/dist/types.d.ts +0 -18
- package/dist/types.js +0 -1
- package/dist/voice.feature.d.ts +0 -1
- package/dist/voice.feature.js +0 -2
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class F{static DEFAULT_MAX_CHUNK_MS=300000;split(j,z=F.DEFAULT_MAX_CHUNK_MS){let q=j.durationMs??this.estimateDurationMs(j);if(q<=z)return[j];let w=[],E=j.data.length/Math.max(q,1),v=0;while(v<q){let A=Math.min(z,q-v),G=Math.floor(v*E),H=Math.floor((v+A)*E);w.push({data:j.data.slice(G,H),format:j.format,sampleRateHz:j.sampleRateHz,durationMs:A,channels:j.channels}),v+=A}return w}estimateDurationMs(j){let q=j.channels??1,w=j.data.length/(2*q);return Math.ceil(w/j.sampleRateHz*1000)}}export{F as SegmentSplitter};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { TranscriptionSegment } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Format transcription segments as SRT or VTT subtitles.
|
|
4
|
-
*/
|
|
5
|
-
export declare class SubtitleFormatter {
|
|
6
|
-
/**
|
|
7
|
-
* Convert segments to SRT format.
|
|
8
|
-
*/
|
|
9
|
-
toSRT(segments: TranscriptionSegment[]): string;
|
|
10
|
-
/**
|
|
11
|
-
* Convert segments to WebVTT format.
|
|
12
|
-
*/
|
|
13
|
-
toVTT(segments: TranscriptionSegment[]): string;
|
|
14
|
-
/** Format ms as SRT timestamp: HH:MM:SS,mmm */
|
|
15
|
-
private formatTimeSRT;
|
|
16
|
-
/** Format ms as VTT timestamp: HH:MM:SS.mmm */
|
|
17
|
-
private formatTimeVTT;
|
|
18
|
-
private pad;
|
|
19
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class A{toSRT(f){return f.map((j,w)=>{let k=this.formatTimeSRT(j.startMs),q=this.formatTimeSRT(j.endMs),x=j.speakerLabel?`[${j.speakerLabel}] `:"";return`${w+1}
|
|
3
|
-
${k} --> ${q}
|
|
4
|
-
${x}${j.text}`}).join(`
|
|
5
|
-
|
|
6
|
-
`)}toVTT(f){return`WEBVTT
|
|
7
|
-
|
|
8
|
-
`+f.map((k,q)=>{let x=this.formatTimeVTT(k.startMs),y=this.formatTimeVTT(k.endMs),z=k.speakerLabel?`<v ${k.speakerLabel}>`:"";return`${q+1}
|
|
9
|
-
${x} --> ${y}
|
|
10
|
-
${z}${k.text}`}).join(`
|
|
11
|
-
|
|
12
|
-
`)}formatTimeSRT(f){let j=Math.floor(f/3600000),w=Math.floor(f%3600000/60000),k=Math.floor(f%60000/1000),q=f%1000;return`${this.pad(j,2)}:${this.pad(w,2)}:${this.pad(k,2)},${this.pad(q,3)}`}formatTimeVTT(f){let j=Math.floor(f/3600000),w=Math.floor(f%3600000/60000),k=Math.floor(f%60000/1000),q=f%1000;return`${this.pad(j,2)}:${this.pad(w,2)}:${this.pad(k,2)}.${this.pad(q,3)}`}pad(f,j){return f.toString().padStart(j,"0")}}export{A as SubtitleFormatter};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { STTBrief, STTOptions, TranscriptionProject, TranscriptionSegment } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Main STT orchestrator.
|
|
4
|
-
*
|
|
5
|
-
* Pipeline:
|
|
6
|
-
* 1. Split audio into processable chunks (if needed)
|
|
7
|
-
* 2. Transcribe via STTProvider
|
|
8
|
-
* 3. Map speaker IDs to labels (if diarization enabled)
|
|
9
|
-
* 4. Format subtitles (if requested)
|
|
10
|
-
*/
|
|
11
|
-
export declare class Transcriber {
|
|
12
|
-
private readonly stt;
|
|
13
|
-
private readonly segmentSplitter;
|
|
14
|
-
private readonly diarizationMapper;
|
|
15
|
-
private readonly subtitleFormatter;
|
|
16
|
-
constructor(options: STTOptions);
|
|
17
|
-
/** Transcribe audio to text */
|
|
18
|
-
transcribe(brief: STTBrief): Promise<TranscriptionProject>;
|
|
19
|
-
/** Stream transcription (real-time, if provider supports it) */
|
|
20
|
-
transcribeStream(audio: AsyncIterable<Uint8Array>, options?: Partial<STTBrief>): AsyncIterable<TranscriptionSegment>;
|
|
21
|
-
}
|
package/dist/stt/transcriber.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class Z{map(q,A="Speaker"){let G=[],w=new Map;for(let E of q)if(E.speakerId&&!G.includes(E.speakerId))G.push(E.speakerId),w.set(E.speakerId,{segmentCount:0,totalSpeakingMs:0});let J=q.map((E)=>{if(!E.speakerId)return E;let L=G.indexOf(E.speakerId),N=`${A} ${L+1}`,R=w.get(E.speakerId);if(!R)return{...E,speakerLabel:N};return R.segmentCount+=1,R.totalSpeakingMs+=E.endMs-E.startMs,{...E,speakerLabel:N}}),K=G.map((E,L)=>{let N=w.get(E);return{id:E,label:`${A} ${L+1}`,segmentCount:N?.segmentCount??0,totalSpeakingMs:N?.totalSpeakingMs??0}});return{segments:J,speakers:K}}}class W{static DEFAULT_MAX_CHUNK_MS=300000;split(q,A=W.DEFAULT_MAX_CHUNK_MS){let G=q.durationMs??this.estimateDurationMs(q);if(G<=A)return[q];let w=[],J=q.data.length/Math.max(G,1),K=0;while(K<G){let E=Math.min(A,G-K),L=Math.floor(K*J),N=Math.floor((K+E)*J);w.push({data:q.data.slice(L,N),format:q.format,sampleRateHz:q.sampleRateHz,durationMs:E,channels:q.channels}),K+=E}return w}estimateDurationMs(q){let G=q.channels??1,w=q.data.length/(2*G);return Math.ceil(w/q.sampleRateHz*1000)}}class _{toSRT(q){return q.map((A,G)=>{let w=this.formatTimeSRT(A.startMs),J=this.formatTimeSRT(A.endMs),K=A.speakerLabel?`[${A.speakerLabel}] `:"";return`${G+1}
|
|
3
|
-
${w} --> ${J}
|
|
4
|
-
${K}${A.text}`}).join(`
|
|
5
|
-
|
|
6
|
-
`)}toVTT(q){return`WEBVTT
|
|
7
|
-
|
|
8
|
-
`+q.map((w,J)=>{let K=this.formatTimeVTT(w.startMs),E=this.formatTimeVTT(w.endMs),L=w.speakerLabel?`<v ${w.speakerLabel}>`:"";return`${J+1}
|
|
9
|
-
${K} --> ${E}
|
|
10
|
-
${L}${w.text}`}).join(`
|
|
11
|
-
|
|
12
|
-
`)}formatTimeSRT(q){let A=Math.floor(q/3600000),G=Math.floor(q%3600000/60000),w=Math.floor(q%60000/1000),J=q%1000;return`${this.pad(A,2)}:${this.pad(G,2)}:${this.pad(w,2)},${this.pad(J,3)}`}formatTimeVTT(q){let A=Math.floor(q/3600000),G=Math.floor(q%3600000/60000),w=Math.floor(q%60000/1000),J=q%1000;return`${this.pad(A,2)}:${this.pad(G,2)}:${this.pad(w,2)}.${this.pad(J,3)}`}pad(q,A){return q.toString().padStart(A,"0")}}class j{stt;segmentSplitter=new W;diarizationMapper=new Z;subtitleFormatter=new _;constructor(q){this.stt=q.stt}async transcribe(q){let A=z(),G=this.segmentSplitter.split(q.audio),w=[],J="",K=0,E=0;for(let U of G){let Y=await this.stt.transcribe({audio:U,language:q.language,diarize:q.diarize,speakerCount:q.speakerCount,wordTimestamps:!0,vocabularyHints:q.vocabularyHints}),V=Y.segments.map((Q)=>({text:Q.text,startMs:Q.startMs+E,endMs:Q.endMs+E,speakerId:Q.speakerId,speakerName:Q.speakerName,confidence:Q.confidence}));w.push(...V),J+=(J?" ":"")+Y.text,K+=Y.durationMs,E+=U.durationMs??0}let L=w,N;if(q.diarize){let U=this.diarizationMapper.map(w);L=U.segments,N=U.speakers}let R={text:J,segments:L,language:q.language??"en",durationMs:K},X,$=q.subtitleFormat??"none";if($==="srt")X=this.subtitleFormatter.toSRT(L);else if($==="vtt")X=this.subtitleFormatter.toVTT(L);return{id:A,transcript:R,subtitles:X,speakers:N}}async*transcribeStream(q,A){if(!this.stt.transcribeStream)throw Error("Streaming transcription not supported by the current STT provider");let G=this.stt.transcribeStream(q,{language:A?.language,diarize:A?.diarize,speakerCount:A?.speakerCount,wordTimestamps:!0,vocabularyHints:A?.vocabularyHints});for await(let w of G)yield{text:w.text,startMs:w.startMs,endMs:w.endMs,speakerId:w.speakerId,speakerLabel:w.speakerName,confidence:w.confidence}}}function z(){let q=Date.now().toString(36),A=Math.random().toString(36).slice(2,8);return`stt_${q}_${A}`}export{j as Transcriber};
|
package/dist/stt/types.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { AudioData, STTProvider, VoiceOptions } from '../types';
|
|
2
|
-
export interface STTBrief {
|
|
3
|
-
audio: AudioData;
|
|
4
|
-
language?: string;
|
|
5
|
-
diarize?: boolean;
|
|
6
|
-
speakerCount?: number;
|
|
7
|
-
vocabularyHints?: string[];
|
|
8
|
-
/** Output subtitle format */
|
|
9
|
-
subtitleFormat?: 'srt' | 'vtt' | 'none';
|
|
10
|
-
}
|
|
11
|
-
export interface TranscriptionProject {
|
|
12
|
-
id: string;
|
|
13
|
-
transcript: TranscriptionResult;
|
|
14
|
-
subtitles?: string;
|
|
15
|
-
speakers?: SpeakerMap[];
|
|
16
|
-
}
|
|
17
|
-
export interface TranscriptionResult {
|
|
18
|
-
text: string;
|
|
19
|
-
segments: TranscriptionSegment[];
|
|
20
|
-
language: string;
|
|
21
|
-
durationMs: number;
|
|
22
|
-
wordTimings?: {
|
|
23
|
-
word: string;
|
|
24
|
-
startMs: number;
|
|
25
|
-
endMs: number;
|
|
26
|
-
}[];
|
|
27
|
-
}
|
|
28
|
-
export interface TranscriptionSegment {
|
|
29
|
-
text: string;
|
|
30
|
-
startMs: number;
|
|
31
|
-
endMs: number;
|
|
32
|
-
speakerId?: string;
|
|
33
|
-
speakerLabel?: string;
|
|
34
|
-
confidence?: number;
|
|
35
|
-
}
|
|
36
|
-
export interface SpeakerMap {
|
|
37
|
-
id: string;
|
|
38
|
-
label: string;
|
|
39
|
-
segmentCount: number;
|
|
40
|
-
totalSpeakingMs: number;
|
|
41
|
-
}
|
|
42
|
-
export interface STTOptions extends VoiceOptions {
|
|
43
|
-
stt: STTProvider;
|
|
44
|
-
}
|
package/dist/stt/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { VoiceTimingMap } from '../types';
|
|
2
|
-
interface NegotiationResult {
|
|
3
|
-
/** Updated timing map with negotiated durations */
|
|
4
|
-
timingMap: VoiceTimingMap;
|
|
5
|
-
/** Per-scene negotiation details */
|
|
6
|
-
adjustments: SceneAdjustment[];
|
|
7
|
-
}
|
|
8
|
-
interface SceneAdjustment {
|
|
9
|
-
sceneId: string;
|
|
10
|
-
originalSceneDurationInFrames: number;
|
|
11
|
-
voiceDurationInFrames: number;
|
|
12
|
-
action: 'no_change' | 'extend_scene' | 'pad_silence' | 'suggest_rate_change';
|
|
13
|
-
suggestedRate?: number;
|
|
14
|
-
finalSceneDurationInFrames: number;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Negotiate duration between voice audio and scene durations.
|
|
18
|
-
*
|
|
19
|
-
* One-pass duration balancing:
|
|
20
|
-
* - Voice fits scene -> no change
|
|
21
|
-
* - Voice > 110% of scene -> suggest rate increase (cap 1.3x), extend scene
|
|
22
|
-
* - Voice < 70% of scene -> suggest rate decrease (floor 0.8x), pad silence
|
|
23
|
-
*/
|
|
24
|
-
export declare class DurationNegotiator {
|
|
25
|
-
private static readonly UPPER_THRESHOLD;
|
|
26
|
-
private static readonly LOWER_THRESHOLD;
|
|
27
|
-
private static readonly MAX_RATE;
|
|
28
|
-
private static readonly MIN_RATE;
|
|
29
|
-
/**
|
|
30
|
-
* Negotiate voice-vs-scene durations.
|
|
31
|
-
*
|
|
32
|
-
* @param timingMap - Voice timing map with per-segment durations
|
|
33
|
-
* @param sceneDurations - Map of sceneId -> original scene duration in frames
|
|
34
|
-
*/
|
|
35
|
-
negotiate(timingMap: VoiceTimingMap, sceneDurations: Map<string, number>): NegotiationResult;
|
|
36
|
-
}
|
|
37
|
-
export {};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class q{static UPPER_THRESHOLD=1.1;static LOWER_THRESHOLD=0.7;static MAX_RATE=1.3;static MIN_RATE=0.8;negotiate(z,A){let v=[],B=z.segments.map((b)=>{let k=A.get(b.sceneId);if(k===void 0)return v.push({sceneId:b.sceneId,originalSceneDurationInFrames:b.recommendedSceneDurationInFrames,voiceDurationInFrames:b.durationInFrames,action:"no_change",finalSceneDurationInFrames:b.recommendedSceneDurationInFrames}),b;let x=b.durationInFrames/k;if(x>q.UPPER_THRESHOLD){let y=Math.min(x,q.MAX_RATE);return v.push({sceneId:b.sceneId,originalSceneDurationInFrames:k,voiceDurationInFrames:b.durationInFrames,action:x>q.MAX_RATE?"extend_scene":"suggest_rate_change",suggestedRate:y,finalSceneDurationInFrames:b.recommendedSceneDurationInFrames}),b}if(x<q.LOWER_THRESHOLD){let y=Math.max(x,q.MIN_RATE);return v.push({sceneId:b.sceneId,originalSceneDurationInFrames:k,voiceDurationInFrames:b.durationInFrames,action:"pad_silence",suggestedRate:y,finalSceneDurationInFrames:k}),{...b,recommendedSceneDurationInFrames:k}}return v.push({sceneId:b.sceneId,originalSceneDurationInFrames:k,voiceDurationInFrames:b.durationInFrames,action:"no_change",finalSceneDurationInFrames:b.recommendedSceneDurationInFrames}),b});return{timingMap:{...z,segments:B},adjustments:v}}}export{q as DurationNegotiator};
|
package/dist/sync/index.d.ts
DELETED
package/dist/sync/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class O{static DEFAULT_WPM=150;estimateSeconds(A,B){let G=B??O.DEFAULT_WPM,H=A.split(/\s+/).filter(Boolean).length;return Math.ceil(H/G*60)}estimateMs(A,B){let G=B??O.DEFAULT_WPM,H=A.split(/\s+/).filter(Boolean).length;return Math.ceil(H/G*60*1000)}estimateWordCount(A,B){let G=B??O.DEFAULT_WPM;return Math.round(A/60*G)}}class L{static UPPER_THRESHOLD=1.1;static LOWER_THRESHOLD=0.7;static MAX_RATE=1.3;static MIN_RATE=0.8;negotiate(A,B){let G=[],H=A.segments.map((z)=>{let q=B.get(z.sceneId);if(q===void 0)return G.push({sceneId:z.sceneId,originalSceneDurationInFrames:z.recommendedSceneDurationInFrames,voiceDurationInFrames:z.durationInFrames,action:"no_change",finalSceneDurationInFrames:z.recommendedSceneDurationInFrames}),z;let J=z.durationInFrames/q;if(J>L.UPPER_THRESHOLD){let K=Math.min(J,L.MAX_RATE);return G.push({sceneId:z.sceneId,originalSceneDurationInFrames:q,voiceDurationInFrames:z.durationInFrames,action:J>L.MAX_RATE?"extend_scene":"suggest_rate_change",suggestedRate:K,finalSceneDurationInFrames:z.recommendedSceneDurationInFrames}),z}if(J<L.LOWER_THRESHOLD){let K=Math.max(J,L.MIN_RATE);return G.push({sceneId:z.sceneId,originalSceneDurationInFrames:q,voiceDurationInFrames:z.durationInFrames,action:"pad_silence",suggestedRate:K,finalSceneDurationInFrames:q}),{...z,recommendedSceneDurationInFrames:q}}return G.push({sceneId:z.sceneId,originalSceneDurationInFrames:q,voiceDurationInFrames:z.durationInFrames,action:"no_change",finalSceneDurationInFrames:z.recommendedSceneDurationInFrames}),z});return{timingMap:{...A,segments:H},adjustments:G}}}class U{durationEstimator=new O;adapt(A){let B=A.scenes.filter((q)=>q.narrationText&&q.narrationText.trim().length>0),G=B.map((q,J)=>{let K=q.narrationText??"";return{sceneId:q.id,text:K,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(K),contentType:this.inferContentType(J,B.length)}}),H=G.map((q)=>q.text).join(" "),z=G.reduce((q,J)=>q+J.estimatedDurationSeconds,0);return{fullText:H,segments:G,estimatedDurationSeconds:z}}inferContentType(A,B){if(A===0)return"intro";if(A===B-1)return"cta";if(A===1&&B>3)return"problem";if(A===B-2&&B>3)return"metric";return"solution"}}class X{calculate(A,B,G=1.15){let H=A.map((q)=>{let J=Math.ceil(q.durationMs/1000*B),K=Math.ceil(J*G),Y=q.wordTimings?.map((Q)=>({word:Q.word,startMs:Q.startMs,endMs:Q.endMs}));return{sceneId:q.sceneId,durationMs:q.durationMs,durationInFrames:J,recommendedSceneDurationInFrames:K,wordTimings:Y}});return{totalDurationMs:A.reduce((q,J)=>q+J.durationMs,0),segments:H,fps:B}}recalculateForFps(A,B){let G=A.segments.map((H)=>{let z=Math.ceil(H.durationMs/1000*B),q=H.recommendedSceneDurationInFrames/Math.max(H.durationInFrames,1);return{...H,durationInFrames:z,recommendedSceneDurationInFrames:Math.ceil(z*q)}});return{...A,segments:G,fps:B}}}export{X as TimingCalculator,U as SceneAdapter,L as DurationNegotiator};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { TTSScript } from '../tts/types';
|
|
2
|
-
interface ScenePlanScene {
|
|
3
|
-
id: string;
|
|
4
|
-
compositionId: string;
|
|
5
|
-
durationInFrames: number;
|
|
6
|
-
narrationText?: string;
|
|
7
|
-
}
|
|
8
|
-
interface ScenePlan {
|
|
9
|
-
scenes: ScenePlanScene[];
|
|
10
|
-
estimatedDurationSeconds: number;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Adapt a video-gen ScenePlan into a TTSScript.
|
|
14
|
-
*
|
|
15
|
-
* Bridges the video-gen domain to the voice TTS domain,
|
|
16
|
-
* preserving scene IDs for timing map correlation.
|
|
17
|
-
*/
|
|
18
|
-
export declare class SceneAdapter {
|
|
19
|
-
private readonly durationEstimator;
|
|
20
|
-
/**
|
|
21
|
-
* Convert a ScenePlan into a TTSScript.
|
|
22
|
-
*
|
|
23
|
-
* Filters out scenes without narration text.
|
|
24
|
-
* Assigns contentType based on scene position (first = intro, last = cta, middle = solution).
|
|
25
|
-
*/
|
|
26
|
-
adapt(scenePlan: ScenePlan): TTSScript;
|
|
27
|
-
private inferContentType;
|
|
28
|
-
}
|
|
29
|
-
export {};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class G{static DEFAULT_WPM=150;estimateSeconds(q,j){let z=j??G.DEFAULT_WPM,H=q.split(/\s+/).filter(Boolean).length;return Math.ceil(H/z*60)}estimateMs(q,j){let z=j??G.DEFAULT_WPM,H=q.split(/\s+/).filter(Boolean).length;return Math.ceil(H/z*60*1000)}estimateWordCount(q,j){let z=j??G.DEFAULT_WPM;return Math.round(q/60*z)}}class L{durationEstimator=new G;adapt(q){let j=q.scenes.filter((B)=>B.narrationText&&B.narrationText.trim().length>0),z=j.map((B,I)=>{let J=B.narrationText??"";return{sceneId:B.id,text:J,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(J),contentType:this.inferContentType(I,j.length)}}),H=z.map((B)=>B.text).join(" "),K=z.reduce((B,I)=>B+I.estimatedDurationSeconds,0);return{fullText:H,segments:z,estimatedDurationSeconds:K}}inferContentType(q,j){if(q===0)return"intro";if(q===j-1)return"cta";if(q===1&&j>3)return"problem";if(q===j-2&&j>3)return"metric";return"solution"}}export{L as SceneAdapter};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { SynthesizedSegment } from '../tts/types';
|
|
2
|
-
import type { VoiceTimingMap } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Calculate timing maps from synthesized segments.
|
|
5
|
-
*
|
|
6
|
-
* Converts SynthesizedSegment[] into a VoiceTimingMap with frame calculations.
|
|
7
|
-
*/
|
|
8
|
-
export declare class TimingCalculator {
|
|
9
|
-
/**
|
|
10
|
-
* Build a timing map from synthesized segments.
|
|
11
|
-
*
|
|
12
|
-
* @param segments - Synthesized audio segments with duration info
|
|
13
|
-
* @param fps - Frames per second for frame calculations
|
|
14
|
-
* @param breathingRoomFactor - Factor to add breathing room (default 1.15)
|
|
15
|
-
*/
|
|
16
|
-
calculate(segments: SynthesizedSegment[], fps: number, breathingRoomFactor?: number): VoiceTimingMap;
|
|
17
|
-
/**
|
|
18
|
-
* Recalculate timing map for a different FPS.
|
|
19
|
-
*/
|
|
20
|
-
recalculateForFps(timingMap: VoiceTimingMap, newFps: number): VoiceTimingMap;
|
|
21
|
-
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class z{calculate(h,j,l=1.15){let f=h.map((b)=>{let k=Math.ceil(b.durationMs/1000*j),x=Math.ceil(k*l),y=b.wordTimings?.map((v)=>({word:v.word,startMs:v.startMs,endMs:v.endMs}));return{sceneId:b.sceneId,durationMs:b.durationMs,durationInFrames:k,recommendedSceneDurationInFrames:x,wordTimings:y}});return{totalDurationMs:h.reduce((b,k)=>b+k.durationMs,0),segments:f,fps:j}}recalculateForFps(h,j){let l=h.segments.map((f)=>{let q=Math.ceil(f.durationMs/1000*j),b=f.recommendedSceneDurationInFrames/Math.max(f.durationInFrames,1);return{...f,durationInFrames:q,recommendedSceneDurationInFrames:Math.ceil(q*b)}});return{...h,segments:l,fps:j}}}export{z as TimingCalculator};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { AudioData, VoicePacingDirective } from '../types';
|
|
2
|
-
import type { SynthesizedSegment } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Assemble synthesized segments into a single audio track.
|
|
5
|
-
*
|
|
6
|
-
* Inserts silence between segments based on pacing directives.
|
|
7
|
-
*/
|
|
8
|
-
export declare class AudioAssembler {
|
|
9
|
-
private readonly concatenator;
|
|
10
|
-
private readonly silenceGenerator;
|
|
11
|
-
/**
|
|
12
|
-
* Assemble segments with silence padding.
|
|
13
|
-
*
|
|
14
|
-
* @param segments - Synthesized audio segments
|
|
15
|
-
* @param directives - Pacing directives for silence timing
|
|
16
|
-
* @param defaultPauseMs - Default pause between segments (default 500ms)
|
|
17
|
-
*/
|
|
18
|
-
assemble(segments: SynthesizedSegment[], directives: VoicePacingDirective[], defaultPauseMs?: number): AudioData;
|
|
19
|
-
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class V{concatenate(j){if(j.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[x]=j;if(!x)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};if(j.length===1)return{...x};let{format:N,sampleRateHz:E}=x,Q=x.channels??1;for(let k of j){if(k.format!==N)throw Error(`Format mismatch: expected ${N}, got ${k.format}`);if(k.sampleRateHz!==E)throw Error(`Sample rate mismatch: expected ${E}, got ${k.sampleRateHz}`)}let J=j.reduce((k,O)=>k+O.data.length,0),K=new Uint8Array(J),q=0;for(let k of j)K.set(k.data,q),q+=k.data.length;let U=j.reduce((k,O)=>k+(O.durationMs??0),0);return{data:K,format:N,sampleRateHz:E,durationMs:U,channels:Q}}}class W{generate(j,x="wav",N=44100,E=1){let Q=Math.ceil(N*j/1000),J=2,K=Q*2*E;return{data:new Uint8Array(K),format:x,sampleRateHz:N,durationMs:j,channels:E}}}class Y{concatenator=new V;silenceGenerator=new W;assemble(j,x,N=500){if(j.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[E]=j;if(!E)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let Q=new Map(x.map((q)=>[q.sceneId,q])),J=E.audio,K=[];for(let q=0;q<j.length;q++){let U=j[q];if(!U)continue;let k=Q.get(U.sceneId),O=k?.leadingSilenceMs??0;if(O>0)K.push(this.silenceGenerator.generate(O,J.format,J.sampleRateHz,J.channels??1));K.push(U.audio);let X=k?.trailingSilenceMs??(q<j.length-1?N:0);if(X>0)K.push(this.silenceGenerator.generate(X,J.format,J.sampleRateHz,J.channels??1))}return this.concatenator.concatenate(K)}}export{Y as AudioAssembler};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ModelSelectionContext, ModelSelector } from '@contractspec/lib.ai-providers/selector-types';
|
|
2
|
-
import type { LLMProvider, VoicePacingDirective } from '../types';
|
|
3
|
-
import type { TTSScriptSegment } from './types';
|
|
4
|
-
export interface EmphasisPlannerOptions {
|
|
5
|
-
llm?: LLMProvider;
|
|
6
|
-
model?: string;
|
|
7
|
-
modelSelector?: ModelSelector;
|
|
8
|
-
selectionContext?: ModelSelectionContext;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Plan emphasis and tone per segment.
|
|
12
|
-
*
|
|
13
|
-
* With LLM: requests fine-grained tone/emphasis analysis.
|
|
14
|
-
* Without LLM: falls back to PaceAnalyzer's content-type mapping.
|
|
15
|
-
*/
|
|
16
|
-
export declare class EmphasisPlanner {
|
|
17
|
-
private readonly llm?;
|
|
18
|
-
private readonly model?;
|
|
19
|
-
private readonly modelSelector?;
|
|
20
|
-
private readonly selectionContext?;
|
|
21
|
-
private readonly paceAnalyzer;
|
|
22
|
-
constructor(options?: EmphasisPlannerOptions);
|
|
23
|
-
/**
|
|
24
|
-
* Plan emphasis and tone directives for segments.
|
|
25
|
-
*
|
|
26
|
-
* Falls back to deterministic mapping if LLM is unavailable.
|
|
27
|
-
*/
|
|
28
|
-
plan(segments: TTSScriptSegment[], baseRate?: number): Promise<VoicePacingDirective[]>;
|
|
29
|
-
private resolveModel;
|
|
30
|
-
private planWithLlm;
|
|
31
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var H={intro:{rate:0.95,emphasis:"normal",tone:"authoritative",leadingSilenceMs:0,trailingSilenceMs:500},problem:{rate:0.9,emphasis:"strong",tone:"urgent",leadingSilenceMs:300,trailingSilenceMs:500},solution:{rate:1,emphasis:"normal",tone:"calm",leadingSilenceMs:300,trailingSilenceMs:500},metric:{rate:0.85,emphasis:"strong",tone:"excited",leadingSilenceMs:300,trailingSilenceMs:600},cta:{rate:0.9,emphasis:"strong",tone:"authoritative",leadingSilenceMs:400,trailingSilenceMs:0},transition:{rate:1.1,emphasis:"reduced",tone:"neutral",leadingSilenceMs:200,trailingSilenceMs:300}};class F{analyze(j,q=1){return j.map((B)=>{let w=H[B.contentType];return{sceneId:B.sceneId,rate:w.rate*q,emphasis:w.emphasis,tone:w.tone,leadingSilenceMs:w.leadingSilenceMs,trailingSilenceMs:w.trailingSilenceMs}})}getDefaults(j){return{...H[j]}}}class J{llm;model;modelSelector;selectionContext;paceAnalyzer;constructor(j){this.llm=j?.llm,this.model=j?.model,this.modelSelector=j?.modelSelector,this.selectionContext=j?.selectionContext,this.paceAnalyzer=new F}async plan(j,q=1){if(!this.llm)return this.paceAnalyzer.analyze(j,q);try{return await this.planWithLlm(j,q)}catch{return this.paceAnalyzer.analyze(j,q)}}async resolveModel(){if(this.model)return this.model;if(this.modelSelector){let j=this.selectionContext??{taskDimension:"reasoning"};return(await this.modelSelector.select(j)).modelId}return}async planWithLlm(j,q){if(!this.llm)return this.paceAnalyzer.analyze(j,q);let B=await this.resolveModel(),D=(await this.llm.chat([{role:"system",content:[{type:"text",text:["You are a voice director planning emphasis and pacing for TTS narration.","For each segment, return a JSON array of directives.","Each directive has: sceneId, rate (0.7-1.3), emphasis (reduced|normal|strong),","tone (neutral|urgent|excited|calm|authoritative), leadingSilenceMs, trailingSilenceMs.","Return ONLY a JSON array, no other text."].join(`
|
|
3
|
-
`)}]},{role:"user",content:[{type:"text",text:JSON.stringify(j.map((v)=>({sceneId:v.sceneId,text:v.text,contentType:v.contentType})))}]}],{model:B,temperature:0.3,responseFormat:"json"})).message.content.find((v)=>v.type==="text");if(!D||D.type!=="text")return this.paceAnalyzer.analyze(j,q);return JSON.parse(D.text).map((v)=>({...v,rate:v.rate*q}))}}export{J as EmphasisPlanner};
|
package/dist/tts/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { AudioAssembler } from './audio-assembler';
|
|
2
|
-
export { EmphasisPlanner } from './emphasis-planner';
|
|
3
|
-
export { PaceAnalyzer } from './pace-analyzer';
|
|
4
|
-
export { SegmentSynthesizer } from './segment-synthesizer';
|
|
5
|
-
export type { PacingConfig, SynthesizedSegment, TTSBrief, TTSOptions, TTSProject, TTSScript, TTSScriptSegment, TTSVoiceConfig, VideoTTSBrief, } from './types';
|
|
6
|
-
export { VoiceSynthesizer } from './voice-synthesizer';
|
package/dist/tts/index.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class H{concatenate(V){if(V.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[q]=V;if(!q)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};if(V.length===1)return{...q};let{format:J,sampleRateHz:K}=q,U=q.channels??1;for(let Z of V){if(Z.format!==J)throw Error(`Format mismatch: expected ${J}, got ${Z.format}`);if(Z.sampleRateHz!==K)throw Error(`Sample rate mismatch: expected ${K}, got ${Z.sampleRateHz}`)}let B=V.reduce((Z,$)=>Z+$.data.length,0),Q=new Uint8Array(B),X=0;for(let Z of V)Q.set(Z.data,X),X+=Z.data.length;let j=V.reduce((Z,$)=>Z+($.durationMs??0),0);return{data:Q,format:J,sampleRateHz:K,durationMs:j,channels:U}}}class O{static DEFAULT_WPM=150;estimateSeconds(V,q){let J=q??O.DEFAULT_WPM,K=V.split(/\s+/).filter(Boolean).length;return Math.ceil(K/J*60)}estimateMs(V,q){let J=q??O.DEFAULT_WPM,K=V.split(/\s+/).filter(Boolean).length;return Math.ceil(K/J*60*1000)}estimateWordCount(V,q){let J=q??O.DEFAULT_WPM;return Math.round(V/60*J)}}class _{generate(V,q="wav",J=44100,K=1){let U=Math.ceil(J*V/1000),B=2,Q=U*2*K;return{data:new Uint8Array(Q),format:q,sampleRateHz:J,durationMs:V,channels:K}}}class T{concatenator=new H;silenceGenerator=new _;assemble(V,q,J=500){if(V.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[K]=V;if(!K)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let U=new Map(q.map((X)=>[X.sceneId,X])),B=K.audio,Q=[];for(let X=0;X<V.length;X++){let j=V[X];if(!j)continue;let Z=U.get(j.sceneId),$=Z?.leadingSilenceMs??0;if($>0)Q.push(this.silenceGenerator.generate($,B.format,B.sampleRateHz,B.channels??1));Q.push(j.audio);let k=Z?.trailingSilenceMs??(X<V.length-1?J:0);if(k>0)Q.push(this.silenceGenerator.generate(k,B.format,B.sampleRateHz,B.channels??1))}return this.concatenator.concatenate(Q)}}var G={intro:{rate:0.95,emphasis:"normal",tone:"authoritative",leadingSilenceMs:0,trailingSilenceMs:500},problem:{rate:0.9,emphasis:"strong",tone:"urgent",leadingSilenceMs:300,trailingSilenceMs:500},solution:{rate:1,emphasis:"normal",tone:"calm",leadingSilenceMs:300,trailingSilenceMs:500},metric:{rate:0.85,emphasis:"strong",tone:"excited",leadingSilenceMs:300,trailingSilenceMs:600},cta:{rate:0.9,emphasis:"strong",tone:"authoritative",leadingSilenceMs:400,trailingSilenceMs:0},transition:{rate:1.1,emphasis:"reduced",tone:"neutral",leadingSilenceMs:200,trailingSilenceMs:300}};class W{analyze(V,q=1){return V.map((J)=>{let K=G[J.contentType];return{sceneId:J.sceneId,rate:K.rate*q,emphasis:K.emphasis,tone:K.tone,leadingSilenceMs:K.leadingSilenceMs,trailingSilenceMs:K.trailingSilenceMs}})}getDefaults(V){return{...G[V]}}}class Y{llm;model;modelSelector;selectionContext;paceAnalyzer;constructor(V){this.llm=V?.llm,this.model=V?.model,this.modelSelector=V?.modelSelector,this.selectionContext=V?.selectionContext,this.paceAnalyzer=new W}async plan(V,q=1){if(!this.llm)return this.paceAnalyzer.analyze(V,q);try{return await this.planWithLlm(V,q)}catch{return this.paceAnalyzer.analyze(V,q)}}async resolveModel(){if(this.model)return this.model;if(this.modelSelector){let V=this.selectionContext??{taskDimension:"reasoning"};return(await this.modelSelector.select(V)).modelId}return}async planWithLlm(V,q){if(!this.llm)return this.paceAnalyzer.analyze(V,q);let J=await this.resolveModel(),U=(await this.llm.chat([{role:"system",content:[{type:"text",text:["You are a voice director planning emphasis and pacing for TTS narration.","For each segment, return a JSON array of directives.","Each directive has: sceneId, rate (0.7-1.3), emphasis (reduced|normal|strong),","tone (neutral|urgent|excited|calm|authoritative), leadingSilenceMs, trailingSilenceMs.","Return ONLY a JSON array, no other text."].join(`
|
|
3
|
-
`)}]},{role:"user",content:[{type:"text",text:JSON.stringify(V.map((Q)=>({sceneId:Q.sceneId,text:Q.text,contentType:Q.contentType})))}]}],{model:J,temperature:0.3,responseFormat:"json"})).message.content.find((Q)=>Q.type==="text");if(!U||U.type!=="text")return this.paceAnalyzer.analyze(V,q);return JSON.parse(U.text).map((Q)=>({...Q,rate:Q.rate*q}))}}class L{tts;constructor(V){this.tts=V}async synthesizeAll(V,q,J){let K=new Map(J.map((B)=>[B.sceneId,B]));return await Promise.all(V.map((B)=>this.synthesizeOne(B,q,K.get(B.sceneId))))}async synthesizeOne(V,q,J){let K=await this.tts.synthesize({text:V.text,voiceId:q.voiceId,language:q.language,style:q.style,stability:q.stability,rate:J?.rate,emphasis:J?.emphasis});return{sceneId:V.sceneId,audio:K.audio,durationMs:K.audio.durationMs??0,wordTimings:K.wordTimings?.map((U)=>({word:U.word,startMs:U.startMs,endMs:U.endMs}))}}}class N{segmentSynthesizer;emphasisPlanner;audioAssembler=new T;durationEstimator=new O;paceAnalyzer=new W;options;constructor(V){this.options=V,this.segmentSynthesizer=new L(V.tts),this.emphasisPlanner=new Y({llm:V.llm,model:V.model})}async synthesize(V){let q=this.buildScript(V);return this.executePipeline(q,V.voice,V.pacing)}async synthesizeForVideo(V){let q=this.buildScriptFromScenePlan(V);return this.executePipeline(q,V.voice,V.pacing,V.fps)}async executePipeline(V,q,J,K){let U=F(),B=J?.baseRate??1,Q=await this.emphasisPlanner.plan(V.segments,B),X=await this.segmentSynthesizer.synthesizeAll(V.segments,q,Q),j=J?.segmentPauseMs??500,Z=this.audioAssembler.assemble(X,Q,j),$=K??this.options.fps??30,k=J?.breathingRoomFactor??1.15,C=this.buildTimingMap(X,$,k);return{id:U,script:V,pacingDirectives:Q,segments:X,assembledAudio:Z,timingMap:C}}buildScript(V){let q=[],J=`${V.content.title}. ${V.content.summary}`;if(q.push({sceneId:"intro",text:J,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(J),contentType:"intro"}),V.content.problems.length>0){let B=V.content.problems.join(". ");q.push({sceneId:"problems",text:B,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(B),contentType:"problem"})}if(V.content.solutions.length>0){let B=V.content.solutions.join(". ");q.push({sceneId:"solutions",text:B,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(B),contentType:"solution"})}if(V.content.metrics&&V.content.metrics.length>0){let B=V.content.metrics.join(". ");q.push({sceneId:"metrics",text:B,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(B),contentType:"metric"})}if(V.content.callToAction)q.push({sceneId:"cta",text:V.content.callToAction,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(V.content.callToAction),contentType:"cta"});let K=q.map((B)=>B.text).join(" "),U=q.reduce((B,Q)=>B+Q.estimatedDurationSeconds,0);return{fullText:K,segments:q,estimatedDurationSeconds:U}}buildScriptFromScenePlan(V){let q=V.scenePlan.scenes.filter((U)=>U.narrationText).map((U)=>{let B=U.narrationText??"";return{sceneId:U.id,text:B,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(B),contentType:"intro"}}),J=q.map((U)=>U.text).join(" "),K=q.reduce((U,B)=>U+B.estimatedDurationSeconds,0);return{fullText:J,segments:q,estimatedDurationSeconds:K}}buildTimingMap(V,q,J){let K=V.map((B)=>{let Q=Math.ceil(B.durationMs/1000*q);return{sceneId:B.sceneId,durationMs:B.durationMs,durationInFrames:Q,recommendedSceneDurationInFrames:Math.ceil(Q*J),wordTimings:B.wordTimings?.map((X)=>({word:X.word,startMs:X.startMs,endMs:X.endMs}))}});return{totalDurationMs:V.reduce((B,Q)=>B+Q.durationMs,0),segments:K,fps:q}}}function F(){let V=Date.now().toString(36),q=Math.random().toString(36).slice(2,8);return`tts_${V}_${q}`}export{N as VoiceSynthesizer,L as SegmentSynthesizer,W as PaceAnalyzer,Y as EmphasisPlanner,T as AudioAssembler};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { VoicePacingDirective } from '../types';
|
|
2
|
-
import type { TTSScriptSegment } from './types';
|
|
3
|
-
type ContentType = TTSScriptSegment['contentType'];
|
|
4
|
-
type Tone = VoicePacingDirective['tone'];
|
|
5
|
-
type Emphasis = VoicePacingDirective['emphasis'];
|
|
6
|
-
interface PacingDefaults {
|
|
7
|
-
rate: number;
|
|
8
|
-
emphasis: Emphasis;
|
|
9
|
-
tone: Tone;
|
|
10
|
-
leadingSilenceMs: number;
|
|
11
|
-
trailingSilenceMs: number;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Analyze content segments and produce pacing directives.
|
|
15
|
-
*
|
|
16
|
-
* Uses a deterministic content-type -> pacing mapping as fallback.
|
|
17
|
-
* When an LLM is provided, can enhance with fine-grained analysis.
|
|
18
|
-
*/
|
|
19
|
-
export declare class PaceAnalyzer {
|
|
20
|
-
/**
|
|
21
|
-
* Generate pacing directives for a list of script segments.
|
|
22
|
-
*
|
|
23
|
-
* @param segments - The TTS script segments to analyze
|
|
24
|
-
* @param baseRate - Base rate multiplier applied to all directives
|
|
25
|
-
*/
|
|
26
|
-
analyze(segments: TTSScriptSegment[], baseRate?: number): VoicePacingDirective[];
|
|
27
|
-
/** Get the default pacing for a content type */
|
|
28
|
-
getDefaults(contentType: ContentType): PacingDefaults;
|
|
29
|
-
}
|
|
30
|
-
export {};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var v={intro:{rate:0.95,emphasis:"normal",tone:"authoritative",leadingSilenceMs:0,trailingSilenceMs:500},problem:{rate:0.9,emphasis:"strong",tone:"urgent",leadingSilenceMs:300,trailingSilenceMs:500},solution:{rate:1,emphasis:"normal",tone:"calm",leadingSilenceMs:300,trailingSilenceMs:500},metric:{rate:0.85,emphasis:"strong",tone:"excited",leadingSilenceMs:300,trailingSilenceMs:600},cta:{rate:0.9,emphasis:"strong",tone:"authoritative",leadingSilenceMs:400,trailingSilenceMs:0},transition:{rate:1.1,emphasis:"reduced",tone:"neutral",leadingSilenceMs:200,trailingSilenceMs:300}};class x{analyze(k,w=1){return k.map((q)=>{let j=v[q.contentType];return{sceneId:q.sceneId,rate:j.rate*w,emphasis:j.emphasis,tone:j.tone,leadingSilenceMs:j.leadingSilenceMs,trailingSilenceMs:j.trailingSilenceMs}})}getDefaults(k){return{...v[k]}}}export{x as PaceAnalyzer};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { TTSProvider, VoicePacingDirective } from '../types';
|
|
2
|
-
import type { SynthesizedSegment, TTSScriptSegment, TTSVoiceConfig } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Synthesize individual script segments via TTSProvider.
|
|
5
|
-
*
|
|
6
|
-
* Applies pacing directives (rate, emphasis) to each synthesis call.
|
|
7
|
-
* Runs segments in parallel via Promise.all().
|
|
8
|
-
*/
|
|
9
|
-
export declare class SegmentSynthesizer {
|
|
10
|
-
private readonly tts;
|
|
11
|
-
constructor(tts: TTSProvider);
|
|
12
|
-
/**
|
|
13
|
-
* Synthesize all segments in parallel.
|
|
14
|
-
*
|
|
15
|
-
* @param segments - Script segments to synthesize
|
|
16
|
-
* @param voice - Voice configuration
|
|
17
|
-
* @param directives - Pacing directives per segment (matched by sceneId)
|
|
18
|
-
*/
|
|
19
|
-
synthesizeAll(segments: TTSScriptSegment[], voice: TTSVoiceConfig, directives: VoicePacingDirective[]): Promise<SynthesizedSegment[]>;
|
|
20
|
-
private synthesizeOne;
|
|
21
|
-
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class C{tts;constructor(j){this.tts=j}async synthesizeAll(j,k,A){let q=new Map(A.map((x)=>[x.sceneId,x]));return await Promise.all(j.map((x)=>this.synthesizeOne(x,k,q.get(x.sceneId))))}async synthesizeOne(j,k,A){let q=await this.tts.synthesize({text:j.text,voiceId:k.voiceId,language:k.language,style:k.style,stability:k.stability,rate:A?.rate,emphasis:A?.emphasis});return{sceneId:j.sceneId,audio:q.audio,durationMs:q.audio.durationMs??0,wordTimings:q.wordTimings?.map((B)=>({word:B.word,startMs:B.startMs,endMs:B.endMs}))}}}export{C as SegmentSynthesizer};
|
package/dist/tts/types.d.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { ContentBrief } from '@contractspec/lib.content-gen/types';
|
|
2
|
-
import type { AudioData, TTSProvider, VoiceOptions, VoicePacingDirective, VoiceTimingMap } from '../types';
|
|
3
|
-
export interface TTSBrief {
|
|
4
|
-
content: ContentBrief;
|
|
5
|
-
voice: TTSVoiceConfig;
|
|
6
|
-
pacing?: PacingConfig;
|
|
7
|
-
targetDurationSeconds?: number;
|
|
8
|
-
locale?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface TTSVoiceConfig {
|
|
11
|
-
voiceId: string;
|
|
12
|
-
language?: string;
|
|
13
|
-
style?: number;
|
|
14
|
-
stability?: number;
|
|
15
|
-
}
|
|
16
|
-
export interface PacingConfig {
|
|
17
|
-
/** Base speaking rate multiplier. Default 1.0 */
|
|
18
|
-
baseRate?: number;
|
|
19
|
-
strategy: 'uniform' | 'dynamic' | 'scene-matched';
|
|
20
|
-
/** Pause between segments in ms. Default 500 */
|
|
21
|
-
segmentPauseMs?: number;
|
|
22
|
-
/** Breathing room factor for scene duration. Default 1.15 */
|
|
23
|
-
breathingRoomFactor?: number;
|
|
24
|
-
}
|
|
25
|
-
export interface TTSProject {
|
|
26
|
-
id: string;
|
|
27
|
-
script: TTSScript;
|
|
28
|
-
pacingDirectives: VoicePacingDirective[];
|
|
29
|
-
segments?: SynthesizedSegment[];
|
|
30
|
-
assembledAudio?: AudioData;
|
|
31
|
-
timingMap?: VoiceTimingMap;
|
|
32
|
-
}
|
|
33
|
-
export interface TTSScript {
|
|
34
|
-
fullText: string;
|
|
35
|
-
segments: TTSScriptSegment[];
|
|
36
|
-
estimatedDurationSeconds: number;
|
|
37
|
-
}
|
|
38
|
-
export interface TTSScriptSegment {
|
|
39
|
-
sceneId: string;
|
|
40
|
-
text: string;
|
|
41
|
-
estimatedDurationSeconds: number;
|
|
42
|
-
contentType: 'intro' | 'problem' | 'solution' | 'metric' | 'cta' | 'transition';
|
|
43
|
-
}
|
|
44
|
-
export interface SynthesizedSegment {
|
|
45
|
-
sceneId: string;
|
|
46
|
-
audio: AudioData;
|
|
47
|
-
durationMs: number;
|
|
48
|
-
wordTimings?: {
|
|
49
|
-
word: string;
|
|
50
|
-
startMs: number;
|
|
51
|
-
endMs: number;
|
|
52
|
-
}[];
|
|
53
|
-
}
|
|
54
|
-
export interface TTSOptions extends VoiceOptions {
|
|
55
|
-
tts: TTSProvider;
|
|
56
|
-
defaultVoiceId?: string;
|
|
57
|
-
fps?: number;
|
|
58
|
-
defaultPacing?: PacingConfig;
|
|
59
|
-
}
|
|
60
|
-
/** Video-aware brief: takes a ScenePlan instead of standalone content */
|
|
61
|
-
export interface VideoTTSBrief {
|
|
62
|
-
content: ContentBrief;
|
|
63
|
-
scenePlan: {
|
|
64
|
-
scenes: {
|
|
65
|
-
id: string;
|
|
66
|
-
compositionId: string;
|
|
67
|
-
durationInFrames: number;
|
|
68
|
-
narrationText?: string;
|
|
69
|
-
}[];
|
|
70
|
-
estimatedDurationSeconds: number;
|
|
71
|
-
};
|
|
72
|
-
voice: TTSVoiceConfig;
|
|
73
|
-
pacing?: PacingConfig;
|
|
74
|
-
fps: number;
|
|
75
|
-
locale?: string;
|
|
76
|
-
}
|
package/dist/tts/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { TTSBrief, TTSOptions, TTSProject, VideoTTSBrief } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Main TTS orchestrator.
|
|
4
|
-
*
|
|
5
|
-
* Pipeline:
|
|
6
|
-
* 1. Build script from content brief (or scene plan)
|
|
7
|
-
* 2. Analyze pacing per segment
|
|
8
|
-
* 3. Plan emphasis/tone
|
|
9
|
-
* 4. Synthesize each segment via TTSProvider
|
|
10
|
-
* 5. Assemble into final audio + timing map
|
|
11
|
-
*/
|
|
12
|
-
export declare class VoiceSynthesizer {
|
|
13
|
-
private readonly segmentSynthesizer;
|
|
14
|
-
private readonly emphasisPlanner;
|
|
15
|
-
private readonly audioAssembler;
|
|
16
|
-
private readonly durationEstimator;
|
|
17
|
-
private readonly paceAnalyzer;
|
|
18
|
-
private readonly options;
|
|
19
|
-
constructor(options: TTSOptions);
|
|
20
|
-
/** Standalone TTS from content brief */
|
|
21
|
-
synthesize(brief: TTSBrief): Promise<TTSProject>;
|
|
22
|
-
/** Scene-aware TTS for video-gen */
|
|
23
|
-
synthesizeForVideo(brief: VideoTTSBrief): Promise<TTSProject>;
|
|
24
|
-
private executePipeline;
|
|
25
|
-
private buildScript;
|
|
26
|
-
private buildScriptFromScenePlan;
|
|
27
|
-
private buildTimingMap;
|
|
28
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
class Y{concatenate(q){if(q.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[J]=q;if(!J)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};if(q.length===1)return{...J};let{format:Q,sampleRateHz:U}=J,Z=J.channels??1;for(let V of q){if(V.format!==Q)throw Error(`Format mismatch: expected ${Q}, got ${V.format}`);if(V.sampleRateHz!==U)throw Error(`Sample rate mismatch: expected ${U}, got ${V.sampleRateHz}`)}let K=q.reduce((V,W)=>V+W.data.length,0),X=new Uint8Array(K),$=0;for(let V of q)X.set(V.data,$),$+=V.data.length;let j=q.reduce((V,W)=>V+(W.durationMs??0),0);return{data:X,format:Q,sampleRateHz:U,durationMs:j,channels:Z}}}class k{static DEFAULT_WPM=150;estimateSeconds(q,J){let Q=J??k.DEFAULT_WPM,U=q.split(/\s+/).filter(Boolean).length;return Math.ceil(U/Q*60)}estimateMs(q,J){let Q=J??k.DEFAULT_WPM,U=q.split(/\s+/).filter(Boolean).length;return Math.ceil(U/Q*60*1000)}estimateWordCount(q,J){let Q=J??k.DEFAULT_WPM;return Math.round(q/60*Q)}}class L{generate(q,J="wav",Q=44100,U=1){let Z=Math.ceil(Q*q/1000),K=2,X=Z*2*U;return{data:new Uint8Array(X),format:J,sampleRateHz:Q,durationMs:q,channels:U}}}class H{concatenator=new Y;silenceGenerator=new L;assemble(q,J,Q=500){if(q.length===0)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let[U]=q;if(!U)return{data:new Uint8Array(0),format:"wav",sampleRateHz:44100,durationMs:0,channels:1};let Z=new Map(J.map(($)=>[$.sceneId,$])),K=U.audio,X=[];for(let $=0;$<q.length;$++){let j=q[$];if(!j)continue;let V=Z.get(j.sceneId),W=V?.leadingSilenceMs??0;if(W>0)X.push(this.silenceGenerator.generate(W,K.format,K.sampleRateHz,K.channels??1));X.push(j.audio);let O=V?.trailingSilenceMs??($<q.length-1?Q:0);if(O>0)X.push(this.silenceGenerator.generate(O,K.format,K.sampleRateHz,K.channels??1))}return this.concatenator.concatenate(X)}}var N={intro:{rate:0.95,emphasis:"normal",tone:"authoritative",leadingSilenceMs:0,trailingSilenceMs:500},problem:{rate:0.9,emphasis:"strong",tone:"urgent",leadingSilenceMs:300,trailingSilenceMs:500},solution:{rate:1,emphasis:"normal",tone:"calm",leadingSilenceMs:300,trailingSilenceMs:500},metric:{rate:0.85,emphasis:"strong",tone:"excited",leadingSilenceMs:300,trailingSilenceMs:600},cta:{rate:0.9,emphasis:"strong",tone:"authoritative",leadingSilenceMs:400,trailingSilenceMs:0},transition:{rate:1.1,emphasis:"reduced",tone:"neutral",leadingSilenceMs:200,trailingSilenceMs:300}};class B{analyze(q,J=1){return q.map((Q)=>{let U=N[Q.contentType];return{sceneId:Q.sceneId,rate:U.rate*J,emphasis:U.emphasis,tone:U.tone,leadingSilenceMs:U.leadingSilenceMs,trailingSilenceMs:U.trailingSilenceMs}})}getDefaults(q){return{...N[q]}}}class _{llm;model;modelSelector;selectionContext;paceAnalyzer;constructor(q){this.llm=q?.llm,this.model=q?.model,this.modelSelector=q?.modelSelector,this.selectionContext=q?.selectionContext,this.paceAnalyzer=new B}async plan(q,J=1){if(!this.llm)return this.paceAnalyzer.analyze(q,J);try{return await this.planWithLlm(q,J)}catch{return this.paceAnalyzer.analyze(q,J)}}async resolveModel(){if(this.model)return this.model;if(this.modelSelector){let q=this.selectionContext??{taskDimension:"reasoning"};return(await this.modelSelector.select(q)).modelId}return}async planWithLlm(q,J){if(!this.llm)return this.paceAnalyzer.analyze(q,J);let Q=await this.resolveModel(),Z=(await this.llm.chat([{role:"system",content:[{type:"text",text:["You are a voice director planning emphasis and pacing for TTS narration.","For each segment, return a JSON array of directives.","Each directive has: sceneId, rate (0.7-1.3), emphasis (reduced|normal|strong),","tone (neutral|urgent|excited|calm|authoritative), leadingSilenceMs, trailingSilenceMs.","Return ONLY a JSON array, no other text."].join(`
|
|
3
|
-
`)}]},{role:"user",content:[{type:"text",text:JSON.stringify(q.map((X)=>({sceneId:X.sceneId,text:X.text,contentType:X.contentType})))}]}],{model:Q,temperature:0.3,responseFormat:"json"})).message.content.find((X)=>X.type==="text");if(!Z||Z.type!=="text")return this.paceAnalyzer.analyze(q,J);return JSON.parse(Z.text).map((X)=>({...X,rate:X.rate*J}))}}class G{tts;constructor(q){this.tts=q}async synthesizeAll(q,J,Q){let U=new Map(Q.map((K)=>[K.sceneId,K]));return await Promise.all(q.map((K)=>this.synthesizeOne(K,J,U.get(K.sceneId))))}async synthesizeOne(q,J,Q){let U=await this.tts.synthesize({text:q.text,voiceId:J.voiceId,language:J.language,style:J.style,stability:J.stability,rate:Q?.rate,emphasis:Q?.emphasis});return{sceneId:q.sceneId,audio:U.audio,durationMs:U.audio.durationMs??0,wordTimings:U.wordTimings?.map((Z)=>({word:Z.word,startMs:Z.startMs,endMs:Z.endMs}))}}}class I{segmentSynthesizer;emphasisPlanner;audioAssembler=new H;durationEstimator=new k;paceAnalyzer=new B;options;constructor(q){this.options=q,this.segmentSynthesizer=new G(q.tts),this.emphasisPlanner=new _({llm:q.llm,model:q.model})}async synthesize(q){let J=this.buildScript(q);return this.executePipeline(J,q.voice,q.pacing)}async synthesizeForVideo(q){let J=this.buildScriptFromScenePlan(q);return this.executePipeline(J,q.voice,q.pacing,q.fps)}async executePipeline(q,J,Q,U){let Z=C(),K=Q?.baseRate??1,X=await this.emphasisPlanner.plan(q.segments,K),$=await this.segmentSynthesizer.synthesizeAll(q.segments,J,X),j=Q?.segmentPauseMs??500,V=this.audioAssembler.assemble($,X,j),W=U??this.options.fps??30,O=Q?.breathingRoomFactor??1.15,F=this.buildTimingMap($,W,O);return{id:Z,script:q,pacingDirectives:X,segments:$,assembledAudio:V,timingMap:F}}buildScript(q){let J=[],Q=`${q.content.title}. ${q.content.summary}`;if(J.push({sceneId:"intro",text:Q,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(Q),contentType:"intro"}),q.content.problems.length>0){let K=q.content.problems.join(". ");J.push({sceneId:"problems",text:K,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(K),contentType:"problem"})}if(q.content.solutions.length>0){let K=q.content.solutions.join(". ");J.push({sceneId:"solutions",text:K,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(K),contentType:"solution"})}if(q.content.metrics&&q.content.metrics.length>0){let K=q.content.metrics.join(". ");J.push({sceneId:"metrics",text:K,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(K),contentType:"metric"})}if(q.content.callToAction)J.push({sceneId:"cta",text:q.content.callToAction,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(q.content.callToAction),contentType:"cta"});let U=J.map((K)=>K.text).join(" "),Z=J.reduce((K,X)=>K+X.estimatedDurationSeconds,0);return{fullText:U,segments:J,estimatedDurationSeconds:Z}}buildScriptFromScenePlan(q){let J=q.scenePlan.scenes.filter((Z)=>Z.narrationText).map((Z)=>{let K=Z.narrationText??"";return{sceneId:Z.id,text:K,estimatedDurationSeconds:this.durationEstimator.estimateSeconds(K),contentType:"intro"}}),Q=J.map((Z)=>Z.text).join(" "),U=J.reduce((Z,K)=>Z+K.estimatedDurationSeconds,0);return{fullText:Q,segments:J,estimatedDurationSeconds:U}}buildTimingMap(q,J,Q){let U=q.map((K)=>{let X=Math.ceil(K.durationMs/1000*J);return{sceneId:K.sceneId,durationMs:K.durationMs,durationInFrames:X,recommendedSceneDurationInFrames:Math.ceil(X*Q),wordTimings:K.wordTimings?.map(($)=>({word:$.word,startMs:$.startMs,endMs:$.endMs}))}});return{totalDurationMs:q.reduce((K,X)=>K+X.durationMs,0),segments:U,fps:J}}}function C(){let q=Date.now().toString(36),J=Math.random().toString(36).slice(2,8);return`tts_${q}_${J}`}export{I as VoiceSynthesizer};
|
package/dist/types.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ContentBrief } from '@contractspec/lib.content-gen/types';
|
|
2
|
-
import type { LLMProvider } from '@contractspec/lib.contracts-integrations/integrations/providers/llm';
|
|
3
|
-
import type { AudioData, AudioFormat, ConversationalEvent, ConversationalProvider, ConversationalSessionSummary, STTProvider, TTSProvider, Voice, WordTiming } from '@contractspec/lib.contracts-integrations/integrations/providers/voice';
|
|
4
|
-
import type { VoicePacingDirective, VoiceTimingMap } from '@contractspec/lib.contracts-integrations/integrations/providers/voice-video-sync';
|
|
5
|
-
export type { AudioData, AudioFormat, ContentBrief, ConversationalEvent, ConversationalProvider, ConversationalSessionSummary, LLMProvider, STTProvider, TTSProvider, Voice, VoicePacingDirective, VoiceTimingMap, WordTiming, };
|
|
6
|
-
/** Shared options base for all voice generators */
|
|
7
|
-
export interface VoiceOptions {
|
|
8
|
-
llm?: LLMProvider;
|
|
9
|
-
model?: string;
|
|
10
|
-
temperature?: number;
|
|
11
|
-
locale?: string;
|
|
12
|
-
/** Transport mode for voice providers. */
|
|
13
|
-
transport?: 'rest' | 'mcp' | 'sdk';
|
|
14
|
-
/** Auth method for voice providers. */
|
|
15
|
-
authMethod?: 'api-key' | 'oauth2' | 'bearer';
|
|
16
|
-
/** Custom auth headers for voice providers. */
|
|
17
|
-
authHeaders?: Record<string, string>;
|
|
18
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// @bun
|
package/dist/voice.feature.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const VoiceFeature: import("@contractspec/lib.contracts-spec").FeatureModuleSpec;
|
package/dist/voice.feature.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{defineFeature as g}from"@contractspec/lib.contracts-spec/features";var j=g({meta:{key:"libs.voice",version:"1.0.0",title:"Voice",description:"Voice capabilities: TTS, STT, and conversational AI",domain:"voice",owners:["@contractspec-core"],tags:["package","libs","voice"],stability:"experimental"}});export{j as VoiceFeature};
|