motionrender 0.2.4 → 0.2.5

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/dist/cli.js CHANGED
@@ -2951,25 +2951,23 @@ function inferChatTask(messages2, options3) {
2951
2951
  return "compose";
2952
2952
  }
2953
2953
  function createProvider(config = {}) {
2954
- const id2 = (config.provider || process.env.OVE_AI_PROVIDER || (process.env.FREELLMAPI_BASE_URL ? "freellmapi" : "") || (process.env.NVIDIA_API_KEY ? "nvidia" : process.env.GROQ_API_KEY ? "groq" : process.env.ANTHROPIC_API_KEY ? "anthropic" : "")).toLowerCase();
2954
+ const id2 = (config.provider || process.env.OVE_AI_PROVIDER || (process.env.FREELLMAPI_BASE_URL || process.env.FREELLMAPI_API_KEY ? "freellmapi" : "") || (process.env.NVIDIA_API_KEY ? "nvidia" : process.env.GROQ_API_KEY ? "groq" : process.env.ANTHROPIC_API_KEY ? "anthropic" : "") || "freellmapi").toLowerCase();
2955
2955
  switch (id2) {
2956
+ case "mock":
2957
+ return new MockProvider();
2956
2958
  case "freellmapi":
2957
2959
  case "openai":
2958
- return attachGroqAudio(new FreeLlmApiProvider(config), config);
2960
+ return new FreeLlmApiProvider(config);
2961
+ case "groq":
2962
+ return new GroqProvider(config);
2959
2963
  case "nvidia":
2960
2964
  case "nim":
2961
2965
  return attachGroqAudio(new NvidiaProvider(config), config);
2962
2966
  case "anthropic":
2963
2967
  case "claude":
2964
2968
  return attachGroqAudio(new AnthropicProvider(config), config);
2965
- case "groq":
2966
- return new GroqProvider(config);
2967
- case "mock":
2968
- return new MockProvider();
2969
- case "":
2970
- throw new Error("No AI provider chosen: pass --provider freellmapi|nvidia|groq|anthropic|mock, or set FREELLMAPI_BASE_URL, NVIDIA_API_KEY, GROQ_API_KEY or ANTHROPIC_API_KEY");
2971
2969
  default:
2972
- throw new Error(`Unknown AI provider "${id2}"; use freellmapi, nvidia, groq, anthropic or mock`);
2970
+ return new FreeLlmApiProvider(config);
2973
2971
  }
2974
2972
  }
2975
2973
  function describeProvider(provider) {
@@ -3259,6 +3257,65 @@ var init_providers = __esm({
3259
3257
  if (!text) throw new Error("FreeLLMAPI chat returned no text. Check active models and upstream keys in your FreeLLMAPI dashboard.");
3260
3258
  return text;
3261
3259
  }
3260
+ async speak(text, options3 = {}) {
3261
+ const response = await request(`${this.baseUrl}/audio/speech`, {
3262
+ method: "POST",
3263
+ signal: timeoutSignal(options3.signal),
3264
+ headers: jsonHeaders(this.headers()),
3265
+ body: JSON.stringify({
3266
+ model: "auto",
3267
+ input: text,
3268
+ voice: options3.voice ?? "alloy"
3269
+ })
3270
+ }, "FreeLLMAPI speech");
3271
+ return { data: new Uint8Array(await response.arrayBuffer()), extension: "mp3" };
3272
+ }
3273
+ async transcribe(audio, filename, options3 = {}) {
3274
+ const form = new FormData();
3275
+ form.append("file", new Blob([audio]), filename || "audio.mp3");
3276
+ form.append("model", "auto");
3277
+ form.append("response_format", "verbose_json");
3278
+ if (options3.language) form.append("language", options3.language);
3279
+ const response = await request(`${this.baseUrl}/audio/transcriptions`, {
3280
+ method: "POST",
3281
+ signal: timeoutSignal(options3.signal),
3282
+ headers: this.headers(),
3283
+ body: form
3284
+ }, "FreeLLMAPI transcription");
3285
+ const data = await response.json();
3286
+ return {
3287
+ text: String(data?.text ?? ""),
3288
+ words: Array.isArray(data?.words) ? data.words.map((w) => ({
3289
+ text: String(w.word ?? w.text ?? ""),
3290
+ start: Number(w.start) || 0,
3291
+ end: Number(w.end) || 0
3292
+ })) : [],
3293
+ cues: Array.isArray(data?.segments) ? data.segments.map((s) => ({
3294
+ text: String(s.text ?? ""),
3295
+ start: Number(s.start) || 0,
3296
+ end: Number(s.end) || 0
3297
+ })) : []
3298
+ };
3299
+ }
3300
+ async image(prompt, options3 = {}) {
3301
+ const size = options3.size ?? "1024x1024";
3302
+ const response = await request(`${this.baseUrl}/images/generations`, {
3303
+ method: "POST",
3304
+ signal: timeoutSignal(options3.signal),
3305
+ headers: jsonHeaders(this.headers()),
3306
+ body: JSON.stringify({
3307
+ model: "auto",
3308
+ prompt,
3309
+ n: 1,
3310
+ size,
3311
+ response_format: "b64_json"
3312
+ })
3313
+ }, "FreeLLMAPI image");
3314
+ const data = await response.json();
3315
+ const b64 = data?.data?.[0]?.b64_json;
3316
+ if (!b64) throw new Error("FreeLLMAPI did not return image data");
3317
+ return { data: Buffer.from(b64, "base64"), extension: "png" };
3318
+ }
3262
3319
  };
3263
3320
  attachGroqAudio = (provider, config) => {
3264
3321
  if (provider.speak || provider.transcribe || !process.env.GROQ_API_KEY) return provider;
@@ -4521,7 +4578,7 @@ function narrationScene(composition, options3) {
4521
4578
  return next;
4522
4579
  }
4523
4580
  async function narrate(provider, options3) {
4524
- if (!provider.speak) throw new Error(`The ${provider.id} provider cannot make speech; use --provider groq (or add a speak() adapter)`);
4581
+ if (!provider.speak) throw new Error(`The ${provider.id} provider cannot make speech (or add a speak() adapter)`);
4525
4582
  const brief = options3.brief?.trim();
4526
4583
  let text = options3.text?.trim() ?? "";
4527
4584
  if (!text && brief) {
@@ -4568,7 +4625,7 @@ async function narrate(provider, options3) {
4568
4625
  return { audio: audioFile, captions: captionsFile, durationSeconds, words: transcript.words.length, composition, text };
4569
4626
  }
4570
4627
  async function captionAudio(provider, options3) {
4571
- if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe; use --provider groq (or add a transcribe() adapter)`);
4628
+ if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe (or add a transcribe() adapter)`);
4572
4629
  const audioFile = resolve6(options3.audio);
4573
4630
  const data = await readFile8(audioFile);
4574
4631
  options3.onProgress?.("Transcribing\u2026");
@@ -4819,7 +4876,7 @@ function editComposition(options3) {
4819
4876
  return composition;
4820
4877
  }
4821
4878
  async function editVideo(provider, options3) {
4822
- if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe; use --provider groq (or add a transcribe() adapter)`);
4879
+ if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe (or add a transcribe() adapter)`);
4823
4880
  const clip2 = resolve7(options3.clip);
4824
4881
  const outDir = resolve7(options3.outDir);
4825
4882
  const width = options3.width ?? 1080, height = options3.height ?? 1920, fps = options3.fps ?? 30;
@@ -4927,7 +4984,7 @@ function shortsCandidatePlan(candidate, cut, maxSilence, keepFillers) {
4927
4984
  return cut ? planCuts(slice, { maxSilence, keepFillers, padding: 0.2 }) : planCuts(slice, { maxSilence: Number.MAX_SAFE_INTEGER, keepFillers: true, padding: 0.2 });
4928
4985
  }
4929
4986
  async function shortsFrom(provider, options3) {
4930
- if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe; use --provider groq (or add a transcribe() adapter)`);
4987
+ if (!provider.transcribe) throw new Error(`The ${provider.id} provider cannot transcribe (or add a transcribe() adapter)`);
4931
4988
  const clip2 = resolve8(options3.clip);
4932
4989
  const outDir = resolve8(options3.outDir);
4933
4990
  const width = options3.width ?? 1080, height = options3.height ?? 1920, fps = options3.fps ?? 30;
@@ -5055,7 +5112,7 @@ function imageSize(size) {
5055
5112
  return sizes[size.toLowerCase()] ?? size;
5056
5113
  }
5057
5114
  async function generateImage(provider, options3) {
5058
- if (!provider.image) throw new Error(`The ${provider.id} provider cannot generate images; use --provider mock (Groq has no image model; or add an image() adapter)`);
5115
+ if (!provider.image) throw new Error(`The ${provider.id} provider cannot generate images (or add an image() adapter)`);
5059
5116
  const generated = await provider.image(options3.prompt, { size: imageSize(options3.size), signal: options3.signal });
5060
5117
  const file2 = resolve9(/\.(png|jpe?g|webp)$/i.test(options3.out) ? options3.out : `${options3.out}.${generated.extension}`);
5061
5118
  await mkdir12(dirname9(file2), { recursive: true });
@@ -130,6 +130,12 @@ export declare class FreeLlmApiProvider implements AiProvider {
130
130
  private headers;
131
131
  resolveModel(task: ChatTask, explicitModel?: string, signal?: AbortSignal): Promise<string>;
132
132
  chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
133
+ speak(text: string, options?: SpeakOptions): Promise<AudioResult>;
134
+ transcribe(audio: Uint8Array, filename: string, options?: {
135
+ language?: string;
136
+ signal?: AbortSignal;
137
+ }): Promise<Transcript>;
138
+ image(prompt: string, options?: ImageOptions): Promise<ImageResult>;
133
139
  }
134
140
  export declare class MockProvider implements AiProvider {
135
141
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "motionrender",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "JSON-first, frame-deterministic motion graphics video engine: render compositions to MP4, WebM, ProRes, GIF or PNG frames from Node or the command line.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -77,4 +77,4 @@
77
77
  "optional": true
78
78
  }
79
79
  }
80
- }
80
+ }