@sogni-ai/sogni-intelligence-client 3.24.2 → 3.24.4

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 (65) hide show
  1. package/dist/client/SogniClientWrapper.d.ts +1 -0
  2. package/dist/client/SogniClientWrapper.d.ts.map +1 -1
  3. package/dist/client/SogniClientWrapper.js +19 -0
  4. package/dist/client/SogniClientWrapper.js.map +1 -1
  5. package/dist/contracts/data/promptContracts.d.ts.map +1 -1
  6. package/dist/contracts/data/promptContracts.js +3 -5
  7. package/dist/contracts/data/promptContracts.js.map +1 -1
  8. package/dist/contracts/imagePrompt.d.ts.map +1 -1
  9. package/dist/contracts/imagePrompt.js +2 -1
  10. package/dist/contracts/imagePrompt.js.map +1 -1
  11. package/dist/contracts/toolPromptMarkers.d.ts +1 -1
  12. package/dist/contracts/toolPromptMarkers.d.ts.map +1 -1
  13. package/dist/contracts/toolPromptMarkers.js +1 -1
  14. package/dist/contracts/toolPromptMarkers.js.map +1 -1
  15. package/dist/openai-tools/_manifests.generated.d.ts.map +1 -1
  16. package/dist/openai-tools/_manifests.generated.js +25 -62
  17. package/dist/openai-tools/_manifests.generated.js.map +1 -1
  18. package/dist/openai-tools/generation-tools.json +25 -62
  19. package/dist/public-skill-runtime/index.d.ts.map +1 -1
  20. package/dist/public-skill-runtime/index.js +108 -31
  21. package/dist/public-skill-runtime/index.js.map +1 -1
  22. package/dist/schemas/tools/animate_photo.schema.json +8 -8
  23. package/dist/schemas/tools/generate_video.schema.json +6 -6
  24. package/dist/schemas/tools/sound_to_video.schema.json +1 -1
  25. package/dist/schemas/tools/video_to_video.schema.json +10 -47
  26. package/dist/tools/definitions/animate-photo/definition.js +1 -1
  27. package/dist/tools/definitions/animate-photo/definition.js.map +1 -1
  28. package/dist/tools/definitions/generate-video/definition.js +3 -3
  29. package/dist/tools/definitions/generate-video/definition.js.map +1 -1
  30. package/dist/tools/definitions/sound-to-video/definition.js +1 -1
  31. package/dist/tools/definitions/sound-to-video/definition.js.map +1 -1
  32. package/dist/tools/definitions/video-to-video/definition.d.ts.map +1 -1
  33. package/dist/tools/definitions/video-to-video/definition.js +11 -39
  34. package/dist/tools/definitions/video-to-video/definition.js.map +1 -1
  35. package/dist/tools/shared/modelRegistry.d.ts.map +1 -1
  36. package/dist/tools/shared/modelRegistry.js +0 -1
  37. package/dist/tools/shared/modelRegistry.js.map +1 -1
  38. package/dist-esm/client/SogniClientWrapper.js +19 -0
  39. package/dist-esm/client/SogniClientWrapper.js.map +1 -1
  40. package/dist-esm/contracts/data/promptContracts.js +3 -5
  41. package/dist-esm/contracts/data/promptContracts.js.map +1 -1
  42. package/dist-esm/contracts/imagePrompt.js +2 -1
  43. package/dist-esm/contracts/imagePrompt.js.map +1 -1
  44. package/dist-esm/contracts/toolPromptMarkers.js +1 -1
  45. package/dist-esm/contracts/toolPromptMarkers.js.map +1 -1
  46. package/dist-esm/openai-tools/_manifests.generated.js +25 -62
  47. package/dist-esm/openai-tools/_manifests.generated.js.map +1 -1
  48. package/dist-esm/openai-tools/generation-tools.json +25 -62
  49. package/dist-esm/public-skill-runtime/index.js +108 -31
  50. package/dist-esm/public-skill-runtime/index.js.map +1 -1
  51. package/dist-esm/schemas/tools/animate_photo.schema.json +8 -8
  52. package/dist-esm/schemas/tools/generate_video.schema.json +6 -6
  53. package/dist-esm/schemas/tools/sound_to_video.schema.json +1 -1
  54. package/dist-esm/schemas/tools/video_to_video.schema.json +10 -47
  55. package/dist-esm/tools/definitions/animate-photo/definition.js +1 -1
  56. package/dist-esm/tools/definitions/animate-photo/definition.js.map +1 -1
  57. package/dist-esm/tools/definitions/generate-video/definition.js +3 -3
  58. package/dist-esm/tools/definitions/generate-video/definition.js.map +1 -1
  59. package/dist-esm/tools/definitions/sound-to-video/definition.js +1 -1
  60. package/dist-esm/tools/definitions/sound-to-video/definition.js.map +1 -1
  61. package/dist-esm/tools/definitions/video-to-video/definition.js +12 -40
  62. package/dist-esm/tools/definitions/video-to-video/definition.js.map +1 -1
  63. package/dist-esm/tools/shared/modelRegistry.js +0 -1
  64. package/dist-esm/tools/shared/modelRegistry.js.map +1 -1
  65. package/package.json +3 -3
@@ -1805,10 +1805,19 @@ export function extractQuotedDialogueSegments(prompt) {
1805
1805
  matches.push(dialogue.trim());
1806
1806
  return ' ';
1807
1807
  });
1808
- const pattern = /"([^"]{1,800})"/g;
1809
- let match;
1810
- while ((match = pattern.exec(untaggedPrompt)) !== null) {
1811
- matches.push(match[1]);
1808
+ const quotePatterns = [
1809
+ /"([^"\r\n]{1,800})"/g,
1810
+ /“([^”\r\n]{1,800})”/g,
1811
+ /‘([^’\r\n]{1,800})’/g,
1812
+ /«([^»\r\n]{1,800})»/g,
1813
+ /「([^」\r\n]{1,800})」/g,
1814
+ /『([^』\r\n]{1,800})』/g,
1815
+ ];
1816
+ for (const pattern of quotePatterns) {
1817
+ let match;
1818
+ while ((match = pattern.exec(untaggedPrompt)) !== null) {
1819
+ matches.push(match[1]);
1820
+ }
1812
1821
  }
1813
1822
  return matches;
1814
1823
  }
@@ -4765,8 +4774,14 @@ function splitStoryboardTableSections(text) {
4765
4774
  ? ''
4766
4775
  : normalizeStoryboardDialogue(extractQuotedDialogueSegments(dialogueCell || audioCell)[0] || dialogueCell || audioCell)
4767
4776
  : '';
4768
- const visibleText = normalizeStoryboardVisibleText(extractStoryboardField(audioCell, ['Visible text', 'On-screen text', 'Onscreen text', 'Text', 'CTA'])
4769
- || (visibleTextHeaderIndex >= 0 ? compactStoryboardLine(visibleTextCell) : ''));
4777
+ const visibleTextHeader = headers?.[visibleTextHeaderIndex] || '';
4778
+ const visibleTextHeaderIsMixedWithAudioOrVoice = visibleTextHeaderIndex >= 0
4779
+ && /\b(?:audio|sfx|sound|foley|music|dialogue|vo|v\.o\.|voiceover|speech|narration)\b/i.test(visibleTextHeader);
4780
+ const explicitlyLabeledVisibleText = extractStoryboardField(audioCell, ['Visible text', 'On-screen text', 'Onscreen text', 'Text overlay', 'Text', 'CTA']);
4781
+ const visibleText = normalizeStoryboardVisibleText(explicitlyLabeledVisibleText
4782
+ || (visibleTextHeaderIndex >= 0 && !visibleTextHeaderIsMixedWithAudioOrVoice
4783
+ ? compactStoryboardLine(visibleTextCell)
4784
+ : ''));
4770
4785
  const audio = extractStoryboardField(audioCell, ['Audio/SFX', 'Audio', 'SFX', 'FX', 'Foley', 'Sound', 'Sounds'])
4771
4786
  || storyboardTableCellWithoutDialogue(soundCell || audioCell, dialogue);
4772
4787
  const transition = extractStoryboardField(transitionCell, ['Transition', 'Transition out', 'Transition-out', 'Edit'])
@@ -4928,34 +4943,79 @@ function splitStoryboardSections(text) {
4928
4943
  return inlineSections;
4929
4944
  return sectionHeadings.length > 0 ? sectionHeadings : tableSections;
4930
4945
  }
4931
- function extractPlainNarrationScriptText(text) {
4946
+ function extractPlainNarrationScriptText(text, allowUnlabeledProse = false) {
4932
4947
  const source = text.trim();
4933
4948
  if (!source)
4934
4949
  return '';
4935
4950
  const markers = Array.from(source.matchAll(/^\s*(?:#{1,6}\s*)?(?:voice[-\s]?over\s+|narration\s+)?script\s*:\s*$/gim));
4936
4951
  const marker = markers[markers.length - 1];
4937
- if (!marker || marker.index === undefined)
4952
+ if (marker?.index !== undefined) {
4953
+ const body = source.slice(marker.index + marker[0].length).trim();
4954
+ return body
4955
+ .split(/\r?\n/)
4956
+ .map(line => stripStoryboardMarkup(line).trim())
4957
+ .filter(Boolean)
4958
+ .join('\n\n')
4959
+ .trim();
4960
+ }
4961
+ if (!allowUnlabeledProse)
4938
4962
  return '';
4939
- const body = source.slice(marker.index + marker[0].length).trim();
4940
- return body
4963
+ return source
4941
4964
  .split(/\r?\n/)
4942
4965
  .map(line => stripStoryboardMarkup(line).trim())
4943
4966
  .filter(Boolean)
4944
4967
  .join('\n\n')
4945
4968
  .trim();
4946
4969
  }
4970
+ function countNarrativeCharacters(text) {
4971
+ return Array.from(text)
4972
+ .filter(character => /[\p{L}\p{N}]/u.test(character))
4973
+ .length;
4974
+ }
4947
4975
  function splitPlainNarrationPhrases(text) {
4948
4976
  const normalized = text
4949
4977
  .replace(/\s+/g, ' ')
4950
4978
  .trim();
4951
4979
  if (!normalized)
4952
4980
  return [];
4953
- const sentenceMatches = normalized.match(/[^.!?]+[.!?]+(?:["')\]]+)?|[^.!?]+$/g) ?? [normalized];
4981
+ const sentenceMatches = [];
4982
+ let sentenceStart = 0;
4983
+ for (let index = 0; index < normalized.length; index += 1) {
4984
+ if (!/[.!?。!?]/u.test(normalized[index]))
4985
+ continue;
4986
+ const terminator = normalized[index];
4987
+ let boundaryEnd = index + 1;
4988
+ while (boundaryEnd < normalized.length && /["'”’»」』)\]]/u.test(normalized[boundaryEnd])) {
4989
+ boundaryEnd += 1;
4990
+ }
4991
+ let nextStart = boundaryEnd;
4992
+ while (nextStart < normalized.length && /\s/.test(normalized[nextStart]))
4993
+ nextStart += 1;
4994
+ const next = normalized[nextStart] ?? '';
4995
+ const hasClosingQuote = boundaryEnd > index + 1;
4996
+ if (hasClosingQuote && /\p{Ll}/u.test(next))
4997
+ continue;
4998
+ if (terminator === '.'
4999
+ && boundaryEnd === nextStart
5000
+ && /\d/.test(normalized[index - 1] ?? '')
5001
+ && /\d/.test(next))
5002
+ continue;
5003
+ const sentence = normalized.slice(sentenceStart, boundaryEnd).trim();
5004
+ if (sentence)
5005
+ sentenceMatches.push(sentence);
5006
+ sentenceStart = nextStart;
5007
+ index = Math.max(index, boundaryEnd - 1);
5008
+ }
5009
+ const tail = normalized.slice(sentenceStart).trim();
5010
+ if (tail)
5011
+ sentenceMatches.push(tail);
5012
+ if (sentenceMatches.length === 0)
5013
+ sentenceMatches.push(normalized);
4954
5014
  return sentenceMatches
4955
5015
  .flatMap(sentence => sentence
4956
5016
  .split(/\s*(?:;|:\s+|,\s+(?=(?:and|but|so|whether|from|across|under|while|as)\b))\s*/i)
4957
5017
  .map(part => compactStoryboardLine(part)))
4958
- .filter(part => countWords(part) > 0);
5018
+ .filter(part => countNarrativeCharacters(part) > 0);
4959
5019
  }
4960
5020
  function splitPhraseAtWordMidpoint(value) {
4961
5021
  const words = value.match(/\S+/g) ?? [];
@@ -5008,9 +5068,10 @@ function titleFromNarrationSegment(segment, index) {
5008
5068
  .join(' ');
5009
5069
  return words || `Narration Beat ${index + 1}`;
5010
5070
  }
5011
- function synthesizeStoryboardSectionsFromPlainNarration(sourceText, frameCount, references) {
5012
- const script = extractPlainNarrationScriptText(sourceText);
5013
- if (!script || countWords(script) < 8)
5071
+ function synthesizeStoryboardSectionsFromPlainNarration(sourceText, frameCount, references, allowUnlabeledProse = false) {
5072
+ const explicitlyLabeledNarration = /^\s*(?:#{1,6}\s*)?(?:voice[-\s]?over\s+|narration\s+)?script\s*:\s*$/im.test(sourceText);
5073
+ const script = extractPlainNarrationScriptText(sourceText, allowUnlabeledProse);
5074
+ if (!script || (countWords(script) < 8 && countNarrativeCharacters(script) < 24))
5014
5075
  return [];
5015
5076
  const phrases = splitPlainNarrationPhrases(script);
5016
5077
  const segments = normalizeNarrationSegmentCount(phrases, frameCount).slice(0, frameCount);
@@ -5025,20 +5086,28 @@ function synthesizeStoryboardSectionsFromPlainNarration(sourceText, frameCount,
5025
5086
  'Detail insert on concrete objects, gestures, text, environment, or visual evidence named in the narration.',
5026
5087
  'Tracking or reveal-style composition that moves the story into the next idea.',
5027
5088
  ];
5028
- return segments.map((segment, index) => ({
5029
- number: index + 1,
5030
- heading: `Scene ${index + 1} - ${titleFromNarrationSegment(segment, index)}`,
5031
- body: [
5032
- `Purpose: Translate narration beat ${index + 1} into a concrete ordered storyboard moment.`,
5033
- `Visual/Action: Create a concrete visual moment using only this narration beat and the supplied references: ${segment}`,
5034
- `Camera/Motion: ${cameraPresets[index % cameraPresets.length]}`,
5035
- 'Lighting/Style: Match the visual style, genre, and tone implied by the user request and supplied references; keep the frame cinematic but readable as a storyboard panel.',
5036
- 'Transition: Maintain continuity from the previous beat through subject, setting, gesture, camera direction, color, or motion when those cues are present.',
5037
- `Dialogue/VO: ${segment}`,
5038
- 'Audio/SFX: Use only audio cues implied by the narration or user request; otherwise keep ambience or music generic and unobtrusive.',
5039
- referenceLine,
5040
- ].filter(Boolean).join('\n'),
5041
- }));
5089
+ return segments.map((segment, index) => {
5090
+ const quotedSpeech = extractQuotedDialogueSegments(segment)
5091
+ .map(item => compactStoryboardLine(item))
5092
+ .filter(Boolean);
5093
+ const dialogue = explicitlyLabeledNarration
5094
+ ? segment
5095
+ : quotedSpeech.join(' ') || '[no dialogue]';
5096
+ return {
5097
+ number: index + 1,
5098
+ heading: `Scene ${index + 1} - ${titleFromNarrationSegment(segment, index)}`,
5099
+ body: [
5100
+ `Purpose: Translate story beat ${index + 1} into a concrete ordered storyboard moment.`,
5101
+ `Visual/Action: Create a concrete visual moment using only this story beat and the supplied references: ${segment}`,
5102
+ `Camera/Motion: ${cameraPresets[index % cameraPresets.length]}`,
5103
+ 'Lighting/Style: Match the visual style, genre, and tone implied by the user request and supplied references; keep the frame cinematic but readable as a storyboard panel.',
5104
+ 'Transition: Maintain continuity from the previous beat through subject, setting, gesture, camera direction, color, or motion when those cues are present.',
5105
+ `Dialogue/VO: ${dialogue}`,
5106
+ 'Audio/SFX: Use only audio cues implied by the story or user request; otherwise keep ambience or music generic and unobtrusive.',
5107
+ referenceLine,
5108
+ ].filter(Boolean).join('\n'),
5109
+ };
5110
+ });
5042
5111
  }
5043
5112
  function storyboardSectionsHavePreservableExplicitTiming(sections) {
5044
5113
  return sections.length > 1
@@ -5283,7 +5352,8 @@ function normalizeStoryboardAudioSfx(value) {
5283
5352
  }
5284
5353
  function buildSceneFromSection(section, references, fallbackTiming, planningContract) {
5285
5354
  const combined = `${section.heading}\n${section.body}`;
5286
- const timing = extractStoryboardTiming(combined) ?? fallbackTiming;
5355
+ const timingSource = `${section.heading.replace(/^\s*(?:[-*+>#_]{1,6}\s*)*(?:[*_]{1,3})?\s*(?:Scene|Shot|Beat|Panel|Frame)\s*_?\s*\d{1,2}\b\s*(?:[-:.)|]\s*)?/i, '')}\n${section.body}`;
5356
+ const timing = extractStoryboardTiming(timingSource) ?? fallbackTiming;
5287
5357
  const normalizedHeading = stripStoryboardMarkup(section.heading)
5288
5358
  .replace(/^\s*#{1,6}\s*/, '');
5289
5359
  const title = compactStoryboardLine(removeStoryboardTimingText(normalizedHeading
@@ -5903,7 +5973,14 @@ export function buildStoryboardProject(options) {
5903
5973
  const selectedSectionsHaveExplicitTiming = sections.length > 0 && storyboardSectionsHavePreservableExplicitTiming(sections);
5904
5974
  const preserveAssistantExplicitTiming = options.promptAuthorship === 'assistant' && selectedSectionsHaveExplicitTiming;
5905
5975
  const synthesizedSections = sections.length === 0
5906
- ? synthesizeStoryboardSectionsFromPlainNarration(`${sourceText}\n\n${narrativeUserIntentText}`, options.frameCount, references)
5976
+ ? [
5977
+ { text: approvedScriptContext, allowUnlabeledProse: true },
5978
+ { text: narrativeUserIntentText, allowUnlabeledProse: false },
5979
+ { text: sourceText, allowUnlabeledProse: false },
5980
+ ]
5981
+ .filter((candidate, index, candidates) => candidate.text && candidates.findIndex(other => other.text === candidate.text) === index)
5982
+ .map(candidate => synthesizeStoryboardSectionsFromPlainNarration(candidate.text, options.frameCount, references, candidate.allowUnlabeledProse))
5983
+ .find(candidate => candidate.length > 0) ?? []
5907
5984
  : [];
5908
5985
  const storyboardSections = sections.length > 0 ? sections : synthesizedSections;
5909
5986
  const parsedScenes = storyboardSections.length > 0