mulmocast 2.9.0 → 2.9.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/lib/actions/movie.d.ts +2 -9
- package/lib/actions/movie.js +149 -147
- package/lib/agents/image_google_agent.d.ts +5 -0
- package/lib/agents/image_google_agent.js +86 -0
- package/lib/agents/movie_google_agent.d.ts +9 -0
- package/lib/agents/movie_google_agent.js +122 -0
- package/lib/agents/mulmo_prompts_agent.d.ts +7 -0
- package/lib/agents/mulmo_prompts_agent.js +37 -0
- package/lib/agents/prompts_data.d.ts +15 -0
- package/lib/agents/prompts_data.js +16 -0
- package/lib/agents/tts_nijivoice_agent.d.ts +5 -0
- package/lib/agents/tts_nijivoice_agent.js +69 -0
- package/lib/agents/validate_mulmo_script_agent.d.ts +17 -0
- package/lib/agents/validate_mulmo_script_agent.js +34 -0
- package/lib/cli/args.d.ts +15 -0
- package/lib/cli/args.js +62 -0
- package/lib/cli/bin.js +0 -0
- package/lib/cli/cli.d.ts +17 -0
- package/lib/cli/cli.js +117 -0
- package/lib/cli/run.d.ts +2 -0
- package/lib/cli/run.js +3 -0
- package/lib/cli/tool-args.d.ts +16 -0
- package/lib/cli/tool-args.js +64 -0
- package/lib/cli/tool-cli.d.ts +2 -0
- package/lib/cli/tool-cli.js +32 -0
- package/lib/cli/tool_commands/prompt/builder.d.ts +4 -0
- package/lib/cli/tool_commands/prompt/builder.js +11 -0
- package/lib/cli/tool_commands/prompt/handler.d.ts +4 -0
- package/lib/cli/tool_commands/prompt/handler.js +14 -0
- package/lib/cli/tool_commands/prompt/index.d.ts +4 -0
- package/lib/cli/tool_commands/prompt/index.js +4 -0
- package/lib/cli/tool_commands/schema/builder.d.ts +2 -0
- package/lib/cli/tool_commands/schema/builder.js +3 -0
- package/lib/cli/tool_commands/schema/handler.d.ts +2 -0
- package/lib/cli/tool_commands/schema/handler.js +12 -0
- package/lib/cli/tool_commands/schema/index.d.ts +4 -0
- package/lib/cli/tool_commands/schema/index.js +4 -0
- package/lib/cli/tool_commands/scripting/builder.d.ts +20 -0
- package/lib/cli/tool_commands/scripting/builder.js +63 -0
- package/lib/cli/tool_commands/scripting/handler.d.ts +12 -0
- package/lib/cli/tool_commands/scripting/handler.js +36 -0
- package/lib/cli/tool_commands/scripting/index.d.ts +4 -0
- package/lib/cli/tool_commands/scripting/index.js +4 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +8 -0
- package/lib/methods/mulmo_beat.d.ts +3 -0
- package/lib/methods/mulmo_beat.js +17 -0
- package/lib/methods/mulmo_beat_node.d.ts +3 -0
- package/lib/methods/mulmo_presentation_style.d.ts +5 -1
- package/lib/methods/mulmo_presentation_style.js +43 -1
- package/lib/methods/mulmo_script_template.d.ts +4 -0
- package/lib/methods/mulmo_script_template.js +6 -0
- package/lib/methods/mulmo_studio.d.ts +8 -0
- package/lib/methods/mulmo_studio.js +25 -0
- package/lib/methods/mulmo_studio_context.d.ts +6 -1
- package/lib/methods/mulmo_studio_context.js +36 -1
- package/lib/slide/blocks.d.ts +13 -0
- package/lib/slide/blocks.js +251 -0
- package/lib/slide/index.d.ts +6 -0
- package/lib/slide/index.js +7 -0
- package/lib/slide/layouts/big_quote.d.ts +2 -0
- package/lib/slide/layouts/big_quote.js +19 -0
- package/lib/slide/layouts/columns.d.ts +2 -0
- package/lib/slide/layouts/columns.js +53 -0
- package/lib/slide/layouts/comparison.d.ts +2 -0
- package/lib/slide/layouts/comparison.js +25 -0
- package/lib/slide/layouts/funnel.d.ts +2 -0
- package/lib/slide/layouts/funnel.js +25 -0
- package/lib/slide/layouts/grid.d.ts +2 -0
- package/lib/slide/layouts/grid.js +38 -0
- package/lib/slide/layouts/index.d.ts +3 -0
- package/lib/slide/layouts/index.js +46 -0
- package/lib/slide/layouts/matrix.d.ts +2 -0
- package/lib/slide/layouts/matrix.js +53 -0
- package/lib/slide/layouts/split.d.ts +2 -0
- package/lib/slide/layouts/split.js +51 -0
- package/lib/slide/layouts/stats.d.ts +2 -0
- package/lib/slide/layouts/stats.js +23 -0
- package/lib/slide/layouts/table.d.ts +2 -0
- package/lib/slide/layouts/table.js +10 -0
- package/lib/slide/layouts/timeline.d.ts +2 -0
- package/lib/slide/layouts/timeline.js +27 -0
- package/lib/slide/layouts/title.d.ts +2 -0
- package/lib/slide/layouts/title.js +19 -0
- package/lib/slide/layouts/waterfall.d.ts +2 -0
- package/lib/slide/layouts/waterfall.js +63 -0
- package/lib/slide/render.d.ts +17 -0
- package/lib/slide/render.js +101 -0
- package/lib/slide/schema.d.ts +9309 -0
- package/lib/slide/schema.js +434 -0
- package/lib/slide/utils.d.ts +76 -0
- package/lib/slide/utils.js +243 -0
- package/lib/tools/prompt.d.ts +1 -0
- package/lib/tools/prompt.js +18 -0
- package/lib/tools/seed.d.ts +3 -0
- package/lib/tools/seed.js +211 -0
- package/lib/tools/seed_from_url.d.ts +3 -0
- package/lib/tools/seed_from_url.js +188 -0
- package/lib/types/slide.d.ts +9309 -0
- package/lib/types/slide.js +434 -0
- package/lib/utils/assets.d.ts +18 -0
- package/lib/utils/assets.js +101 -0
- package/lib/utils/cli.d.ts +1 -0
- package/lib/utils/cli.js +15 -0
- package/lib/utils/const.d.ts +12 -0
- package/lib/utils/const.js +12 -0
- package/lib/utils/filters.js +11 -2
- package/lib/utils/image_preprocess.d.ts +14 -0
- package/lib/utils/image_preprocess.js +52 -0
- package/lib/utils/markdown.d.ts +3 -0
- package/lib/utils/markdown.js +42 -0
- package/lib/utils/pdf.d.ts +9 -0
- package/lib/utils/pdf.js +77 -0
- package/lib/utils/preprocess.d.ts +343 -0
- package/lib/utils/preprocess.js +58 -0
- package/lib/utils/provider2agent.d.ts +141 -0
- package/lib/utils/provider2agent.js +267 -0
- package/lib/utils/text_hash.d.ts +1 -0
- package/lib/utils/text_hash.js +4 -0
- package/package.json +8 -8
- package/scripts/test/test_voice_over_transition_no_audio.json +71 -0
- package/lib/utils/sdk_timeout.d.ts +0 -3
- package/lib/utils/sdk_timeout.js +0 -7
- package/scripts/test/test_captions_2.json~ +0 -278
- package/scripts/test/test_en_portrait.json~ +0 -31
- package/scripts/test/test_slide_image_ref_gemini_en.json~ +0 -289
- package/scripts/test/test_vertexai.json~ +0 -21
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/** Escape HTML special characters */
|
|
2
|
+
export const escapeHtml = (s) => {
|
|
3
|
+
return String(s || "")
|
|
4
|
+
.replace(/&/g, "&")
|
|
5
|
+
.replace(/</g, "<")
|
|
6
|
+
.replace(/>/g, ">")
|
|
7
|
+
.replace(/"/g, """)
|
|
8
|
+
.replace(/'/g, "'");
|
|
9
|
+
};
|
|
10
|
+
/** Escape HTML and convert newlines to <br> */
|
|
11
|
+
export const nl2br = (s) => {
|
|
12
|
+
return escapeHtml(s).replace(/\n/g, "<br>");
|
|
13
|
+
};
|
|
14
|
+
/** Valid accent color keys for inline markup */
|
|
15
|
+
const inlineColorKeys = new Set(["primary", "accent", "success", "warning", "danger", "info", "highlight"]);
|
|
16
|
+
/**
|
|
17
|
+
* Render inline markup: escape HTML first, then parse **bold** and {color:text}.
|
|
18
|
+
* Also converts newlines to <br>.
|
|
19
|
+
* Safe: escapeHtml runs before any markup parsing, so XSS is impossible.
|
|
20
|
+
*/
|
|
21
|
+
export const renderInlineMarkup = (s) => {
|
|
22
|
+
let result = escapeHtml(s);
|
|
23
|
+
// **bold** → <strong>bold</strong>
|
|
24
|
+
result = result.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
25
|
+
// {color:text} → <span class="text-d-color">text</span>
|
|
26
|
+
result = result.replace(/\{([a-z]+):(.+?)\}/g, (_match, color, text) => {
|
|
27
|
+
if (inlineColorKeys.has(color)) {
|
|
28
|
+
return `<span class="text-${c(color)}">${text}</span>`;
|
|
29
|
+
}
|
|
30
|
+
return `{${color}:${text}}`;
|
|
31
|
+
});
|
|
32
|
+
// newlines to <br>
|
|
33
|
+
result = result.replace(/\n/g, "<br>");
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
/** Sanitize a value for safe use in CSS class names (alphanumeric + hyphens only) */
|
|
37
|
+
const sanitizeCssClass = (s) => {
|
|
38
|
+
return s.replace(/[^a-zA-Z0-9-]/g, "");
|
|
39
|
+
};
|
|
40
|
+
/** Sanitize a hex color value (hex digits only) */
|
|
41
|
+
export const sanitizeHex = (s) => {
|
|
42
|
+
return s.replace(/[^0-9A-Fa-f]/g, "");
|
|
43
|
+
};
|
|
44
|
+
/** Accent color key → Tailwind class segment: "primary" → "d-primary" */
|
|
45
|
+
export const c = (key) => {
|
|
46
|
+
return `d-${sanitizeCssClass(key)}`;
|
|
47
|
+
};
|
|
48
|
+
// ═══════════════════════════════════════════════════════════
|
|
49
|
+
// Shared micro-helpers for HTML generation
|
|
50
|
+
// ═══════════════════════════════════════════════════════════
|
|
51
|
+
/** Default accent color used when none is specified */
|
|
52
|
+
const DEFAULT_ACCENT = "primary";
|
|
53
|
+
/** Resolve accent color key with "primary" as fallback */
|
|
54
|
+
export const resolveAccent = (color) => color || DEFAULT_ACCENT;
|
|
55
|
+
/** Resolve item-level color with slide-level fallback then "primary" */
|
|
56
|
+
export const resolveItemColor = (itemColor, slideAccent) => itemColor || slideAccent || DEFAULT_ACCENT;
|
|
57
|
+
/** Render a horizontal accent bar (3px full-width). Pass extraClass for width/margin variants. */
|
|
58
|
+
export const accentBar = (colorKey, extraClass) => `<div class="h-[3px] bg-${c(colorKey)} shrink-0 ${extraClass || ""}"></div>`;
|
|
59
|
+
/** Render an optional block title (chart, mermaid, table) */
|
|
60
|
+
export const blockTitle = (title) => title ? `<p class="text-sm font-bold text-d-text font-body mb-2">${renderInlineMarkup(title)}</p>` : "";
|
|
61
|
+
/** Resolve change indicator color: "success" for positive (+), "danger" for negative */
|
|
62
|
+
export const resolveChangeColor = (change) => (/\+/.test(change) ? "success" : "danger");
|
|
63
|
+
/** Render the optional callout bar at the bottom of a slide, or empty string */
|
|
64
|
+
export const renderOptionalCallout = (callout) => {
|
|
65
|
+
if (!callout)
|
|
66
|
+
return "";
|
|
67
|
+
return `<div class="mt-auto pb-4">${renderCalloutBar(callout)}</div>`;
|
|
68
|
+
};
|
|
69
|
+
const colorKeyMap = {
|
|
70
|
+
bg: "bg",
|
|
71
|
+
bgCard: "card",
|
|
72
|
+
bgCardAlt: "alt",
|
|
73
|
+
text: "text",
|
|
74
|
+
textMuted: "muted",
|
|
75
|
+
textDim: "dim",
|
|
76
|
+
primary: "primary",
|
|
77
|
+
accent: "accent",
|
|
78
|
+
success: "success",
|
|
79
|
+
warning: "warning",
|
|
80
|
+
danger: "danger",
|
|
81
|
+
info: "info",
|
|
82
|
+
highlight: "highlight",
|
|
83
|
+
};
|
|
84
|
+
/** Build the Tailwind config JSON string for theme colors and fonts */
|
|
85
|
+
export const buildTailwindConfig = (theme) => {
|
|
86
|
+
const colorMap = {};
|
|
87
|
+
Object.entries(theme.colors).forEach(([k, v]) => {
|
|
88
|
+
const mapped = colorKeyMap[k];
|
|
89
|
+
if (mapped) {
|
|
90
|
+
colorMap[mapped] = `#${v}`;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return JSON.stringify({
|
|
94
|
+
theme: {
|
|
95
|
+
extend: {
|
|
96
|
+
colors: { d: colorMap },
|
|
97
|
+
fontFamily: {
|
|
98
|
+
title: [theme.fonts.title, "serif"],
|
|
99
|
+
body: [theme.fonts.body, "Arial", "sans-serif"],
|
|
100
|
+
mono: [theme.fonts.mono, "monospace"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
/** Render a numbered circle badge */
|
|
107
|
+
export const numBadge = (num, colorKey) => {
|
|
108
|
+
return `<div class="w-10 h-10 rounded-full bg-${c(colorKey)} flex items-center justify-center shrink-0">
|
|
109
|
+
<span class="text-white font-bold text-sm">${num}</span>
|
|
110
|
+
</div>`;
|
|
111
|
+
};
|
|
112
|
+
/** Render an icon in a square container */
|
|
113
|
+
export const iconSquare = (icon, colorKey) => {
|
|
114
|
+
return `<div class="w-16 h-16 bg-d-alt flex items-center justify-center rounded">
|
|
115
|
+
<span class="text-2xl font-mono font-bold text-${c(colorKey)}">${escapeHtml(icon)}</span>
|
|
116
|
+
</div>`;
|
|
117
|
+
};
|
|
118
|
+
/** Render a card wrapper with accent top bar */
|
|
119
|
+
export const cardWrap = (accentColor, innerHtml, extraClass) => {
|
|
120
|
+
return `<div class="bg-d-card rounded-lg shadow-lg overflow-hidden flex flex-col min-h-0 ${sanitizeCssClass(extraClass || "")}">
|
|
121
|
+
${accentBar(accentColor)}
|
|
122
|
+
<div class="p-5 flex flex-col flex-1 min-h-0 overflow-hidden">
|
|
123
|
+
${innerHtml}
|
|
124
|
+
</div>
|
|
125
|
+
</div>`;
|
|
126
|
+
};
|
|
127
|
+
/** Render a callout bar at the bottom of a slide */
|
|
128
|
+
export const renderCalloutBar = (obj) => {
|
|
129
|
+
const color = obj.color || "warning";
|
|
130
|
+
const leftBar = obj.leftBar ? `<div class="w-1 bg-${c(color)} shrink-0"></div>` : "";
|
|
131
|
+
const align = obj.align === "center" ? "text-center" : "";
|
|
132
|
+
const inner = obj.label
|
|
133
|
+
? `<span class="font-bold text-${c(color)}">${renderInlineMarkup(obj.label)}:</span> <span class="text-d-muted">${renderInlineMarkup(obj.text)}</span>`
|
|
134
|
+
: `<span class="text-d-muted">${renderInlineMarkup(obj.text)}</span>`;
|
|
135
|
+
return `<div class="mx-12 bg-d-card rounded flex overflow-hidden ${align}">
|
|
136
|
+
${leftBar}
|
|
137
|
+
<div class="px-4 py-3 text-sm font-body flex-1">${inner}</div>
|
|
138
|
+
</div>`;
|
|
139
|
+
};
|
|
140
|
+
/** Render header text elements (stepLabel + title + subtitle) without wrapping div */
|
|
141
|
+
export const renderHeaderText = (data) => {
|
|
142
|
+
const accent = resolveAccent(data.accentColor);
|
|
143
|
+
const lines = [];
|
|
144
|
+
if (data.stepLabel) {
|
|
145
|
+
lines.push(`<p class="text-sm font-bold text-${c(accent)} font-body">${renderInlineMarkup(data.stepLabel)}</p>`);
|
|
146
|
+
}
|
|
147
|
+
lines.push(`<h2 class="text-[42px] leading-tight font-title font-bold text-d-text">${renderInlineMarkup(data.title)}</h2>`);
|
|
148
|
+
if (data.subtitle) {
|
|
149
|
+
lines.push(`<p class="text-[15px] text-d-dim mt-2 font-body">${renderInlineMarkup(data.subtitle)}</p>`);
|
|
150
|
+
}
|
|
151
|
+
return lines.join("\n");
|
|
152
|
+
};
|
|
153
|
+
/** Render the common slide header (accent bar + title + subtitle) */
|
|
154
|
+
export const slideHeader = (data) => {
|
|
155
|
+
const accent = resolveAccent(data.accentColor);
|
|
156
|
+
return [accentBar(accent), `<div class="px-12 pt-5 shrink-0">`, renderHeaderText(data), `</div>`].join("\n");
|
|
157
|
+
};
|
|
158
|
+
/** Render accent bar + vertically-centered wrapper with header text (used by stats, timeline) */
|
|
159
|
+
export const centeredSlideHeader = (data) => {
|
|
160
|
+
const accent = resolveAccent(data.accentColor);
|
|
161
|
+
return [accentBar(accent), `<div class="flex-1 flex flex-col justify-center px-12 min-h-0">`, renderHeaderText(data)].join("\n");
|
|
162
|
+
};
|
|
163
|
+
// ═══════════════════════════════════════════════════════════
|
|
164
|
+
// Counter-based ID generation (unique within a single slide)
|
|
165
|
+
// ═══════════════════════════════════════════════════════════
|
|
166
|
+
let slideIdCounter = 0;
|
|
167
|
+
/** Generate a unique ID with the given prefix (e.g. "chart-0", "mermaid-1") */
|
|
168
|
+
export const generateSlideId = (prefix) => `${prefix}-${slideIdCounter++}`;
|
|
169
|
+
/** Reset the ID counter (for testing) */
|
|
170
|
+
export const resetSlideIdCounter = () => {
|
|
171
|
+
slideIdCounter = 0;
|
|
172
|
+
};
|
|
173
|
+
// ═══════════════════════════════════════════════════════════
|
|
174
|
+
// Content block type detection
|
|
175
|
+
// ═══════════════════════════════════════════════════════════
|
|
176
|
+
/** Chart.js plugin CDN URLs keyed by chart type */
|
|
177
|
+
const CHART_PLUGIN_CDNS = {
|
|
178
|
+
sankey: "https://cdn.jsdelivr.net/npm/chartjs-chart-sankey",
|
|
179
|
+
treemap: "https://cdn.jsdelivr.net/npm/chartjs-chart-treemap@3",
|
|
180
|
+
};
|
|
181
|
+
/** Collect all content block arrays from a slide layout */
|
|
182
|
+
const collectContentArrays = (slide) => {
|
|
183
|
+
const arrays = [];
|
|
184
|
+
const pushIfPresent = (content) => {
|
|
185
|
+
if (content)
|
|
186
|
+
arrays.push(content);
|
|
187
|
+
};
|
|
188
|
+
switch (slide.layout) {
|
|
189
|
+
case "columns":
|
|
190
|
+
slide.columns.forEach((col) => pushIfPresent(col.content));
|
|
191
|
+
break;
|
|
192
|
+
case "comparison":
|
|
193
|
+
pushIfPresent(slide.left.content);
|
|
194
|
+
pushIfPresent(slide.right.content);
|
|
195
|
+
break;
|
|
196
|
+
case "grid":
|
|
197
|
+
slide.items.forEach((item) => pushIfPresent(item.content));
|
|
198
|
+
break;
|
|
199
|
+
case "split":
|
|
200
|
+
pushIfPresent(slide.left?.content);
|
|
201
|
+
pushIfPresent(slide.right?.content);
|
|
202
|
+
break;
|
|
203
|
+
case "matrix":
|
|
204
|
+
slide.cells.forEach((cell) => pushIfPresent(cell.content));
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
return arrays;
|
|
208
|
+
};
|
|
209
|
+
/** Collect chart type from a chart block */
|
|
210
|
+
const collectChartPlugin = (block, plugins) => {
|
|
211
|
+
if (block.type === "chart") {
|
|
212
|
+
const chartType = block.chartData?.type;
|
|
213
|
+
if (chartType && CHART_PLUGIN_CDNS[chartType]) {
|
|
214
|
+
plugins.add(CHART_PLUGIN_CDNS[chartType]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
/** Detect whether chart or mermaid content blocks exist in a slide */
|
|
219
|
+
export const detectBlockTypes = (slide) => {
|
|
220
|
+
const arrays = collectContentArrays(slide);
|
|
221
|
+
let hasChart = false;
|
|
222
|
+
let hasMermaid = false;
|
|
223
|
+
const plugins = new Set();
|
|
224
|
+
arrays.forEach((blocks) => {
|
|
225
|
+
blocks.forEach((block) => {
|
|
226
|
+
if (block.type === "chart")
|
|
227
|
+
hasChart = true;
|
|
228
|
+
if (block.type === "mermaid")
|
|
229
|
+
hasMermaid = true;
|
|
230
|
+
collectChartPlugin(block, plugins);
|
|
231
|
+
if (block.type === "section" && block.content) {
|
|
232
|
+
block.content.forEach((inner) => {
|
|
233
|
+
if (inner.type === "chart")
|
|
234
|
+
hasChart = true;
|
|
235
|
+
if (inner.type === "mermaid")
|
|
236
|
+
hasMermaid = true;
|
|
237
|
+
collectChartPlugin(inner, plugins);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
return { hasChart, hasMermaid, chartPlugins: [...plugins] };
|
|
243
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = path.dirname(__filename);
|
|
6
|
+
const main = async () => {
|
|
7
|
+
const basePath = path.resolve(__dirname, "../../prompts/");
|
|
8
|
+
const ret = {};
|
|
9
|
+
fs.readdirSync(basePath).map((file) => {
|
|
10
|
+
const key = file.split(".")[0];
|
|
11
|
+
const content = fs.readFileSync(path.resolve(basePath, file), "utf-8");
|
|
12
|
+
ret[key] = content;
|
|
13
|
+
});
|
|
14
|
+
const code = ["// This file is auto-generated by src/tools/prompt.ts and Do not be edited manually.", `export const prompts = ${JSON.stringify(ret)};`].join("\n");
|
|
15
|
+
fs.writeFileSync(path.resolve(__dirname, "../../src/agents/prompts_data.ts"), code, "utf8");
|
|
16
|
+
// console.log(hoge);
|
|
17
|
+
};
|
|
18
|
+
main();
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createMulmoScriptWithInteractive = void 0;
|
|
37
|
+
require("dotenv/config");
|
|
38
|
+
const graphai_1 = require("graphai");
|
|
39
|
+
const input_agents_1 = require("@graphai/input_agents");
|
|
40
|
+
const openai_agent_1 = require("@graphai/openai_agent");
|
|
41
|
+
const vanilla = __importStar(require("@graphai/vanilla"));
|
|
42
|
+
const vanilla_node_agents_1 = require("@graphai/vanilla_node_agents");
|
|
43
|
+
const file_1 = require("../utils/file");
|
|
44
|
+
const filters_1 = require("../utils/filters");
|
|
45
|
+
const browserless_agent_1 = require("@graphai/browserless_agent");
|
|
46
|
+
const agentHeader = "\x1b[34m● \x1b[0m\x1b[1mAgent\x1b[0m:\x1b[0m";
|
|
47
|
+
const graphDataForScraping = {
|
|
48
|
+
version: 0.5,
|
|
49
|
+
nodes: {
|
|
50
|
+
urls: {
|
|
51
|
+
value: [],
|
|
52
|
+
},
|
|
53
|
+
fetchResults: {
|
|
54
|
+
agent: "mapAgent",
|
|
55
|
+
inputs: {
|
|
56
|
+
rows: ":urls",
|
|
57
|
+
},
|
|
58
|
+
params: {
|
|
59
|
+
compositeResult: true,
|
|
60
|
+
},
|
|
61
|
+
graph: {
|
|
62
|
+
nodes: {
|
|
63
|
+
fetcher: {
|
|
64
|
+
agent: "browserlessAgent",
|
|
65
|
+
inputs: {
|
|
66
|
+
url: ":row",
|
|
67
|
+
text_content: true,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
copyAgent: {
|
|
71
|
+
agent: "copyAgent",
|
|
72
|
+
inputs: {
|
|
73
|
+
text: '{ url: "${:row}", text: "${:fetcher.text}" }',
|
|
74
|
+
},
|
|
75
|
+
params: {
|
|
76
|
+
namedKey: "text",
|
|
77
|
+
},
|
|
78
|
+
isResult: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
sourceText: {
|
|
84
|
+
agent: "arrayJoinAgent",
|
|
85
|
+
inputs: {
|
|
86
|
+
array: ":fetchResults.copyAgent",
|
|
87
|
+
},
|
|
88
|
+
params: {
|
|
89
|
+
separator: ",",
|
|
90
|
+
},
|
|
91
|
+
isResult: true,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const graphData = {
|
|
96
|
+
version: 0.5,
|
|
97
|
+
loop: {
|
|
98
|
+
while: ":continue",
|
|
99
|
+
},
|
|
100
|
+
nodes: {
|
|
101
|
+
fileName: {
|
|
102
|
+
update: ":fileName",
|
|
103
|
+
},
|
|
104
|
+
outdir: {
|
|
105
|
+
update: ":outdir",
|
|
106
|
+
},
|
|
107
|
+
messages: {
|
|
108
|
+
value: [],
|
|
109
|
+
update: ":llm.messages",
|
|
110
|
+
},
|
|
111
|
+
userInput: {
|
|
112
|
+
agent: "textInputAgent",
|
|
113
|
+
params: {
|
|
114
|
+
message: "You:",
|
|
115
|
+
required: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
llm: {
|
|
119
|
+
agent: "openAIAgent",
|
|
120
|
+
params: {
|
|
121
|
+
model: "gpt-4o",
|
|
122
|
+
},
|
|
123
|
+
inputs: {
|
|
124
|
+
messages: ":messages",
|
|
125
|
+
prompt: ":userInput.text",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
json: {
|
|
129
|
+
agent: "copyAgent",
|
|
130
|
+
inputs: {
|
|
131
|
+
json: ":llm.text.codeBlock().jsonParse()",
|
|
132
|
+
text: ":llm.text.codeBlock()",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
writeJSON: {
|
|
136
|
+
if: ":json.json",
|
|
137
|
+
agent: "fileWriteAgent",
|
|
138
|
+
inputs: {
|
|
139
|
+
file: "${:outdir}/${:fileName}-${@now}.json",
|
|
140
|
+
text: ":json.text",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
writeLog: {
|
|
144
|
+
agent: "consoleAgent",
|
|
145
|
+
inputs: {
|
|
146
|
+
text: "\n\x1b[32m🎉 Script file generated successfully! Type /bye to exit.\x1b[0m\nwriting: ${:writeJSON.path}",
|
|
147
|
+
waiting: ":writeJSON",
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
shouldResponse: {
|
|
151
|
+
agent: "compareAgent",
|
|
152
|
+
inputs: {
|
|
153
|
+
array: [[":json.json", "==", undefined], "&&", [":userInput.text", "!=", "/bye"]],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
agentResponse: {
|
|
157
|
+
if: ":shouldResponse.result",
|
|
158
|
+
agent: "consoleAgent",
|
|
159
|
+
inputs: {
|
|
160
|
+
text: "\n" + agentHeader + " ${:llm.text}\n",
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
checkInput: {
|
|
164
|
+
agent: "compareAgent",
|
|
165
|
+
inputs: { array: [":userInput.text", "!=", "/bye"] },
|
|
166
|
+
},
|
|
167
|
+
continue: {
|
|
168
|
+
value: true,
|
|
169
|
+
update: ":checkInput.result",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
const interactiveClarificationPrompt = `If there are any unclear points, be sure to ask the user questions and clarify them before generating the script.`;
|
|
174
|
+
const scrapeWebContent = async (urls, cacheDirPath) => {
|
|
175
|
+
(0, file_1.mkdir)(cacheDirPath);
|
|
176
|
+
console.log(`${agentHeader} Scraping ${urls.length} URLs...\n`);
|
|
177
|
+
const browserlessCache = (0, filters_1.browserlessCacheGenerator)(cacheDirPath);
|
|
178
|
+
const agentFilters = [
|
|
179
|
+
{
|
|
180
|
+
name: "browserlessCache",
|
|
181
|
+
agent: browserlessCache,
|
|
182
|
+
nodeIds: ["fetcher"],
|
|
183
|
+
},
|
|
184
|
+
];
|
|
185
|
+
const graph = new graphai_1.GraphAI(graphDataForScraping, { ...vanilla, openAIAgent: openai_agent_1.openAIAgent, textInputAgent: input_agents_1.textInputAgent, fileWriteAgent: vanilla_node_agents_1.fileWriteAgent, browserlessAgent: browserless_agent_1.browserlessAgent }, { agentFilters });
|
|
186
|
+
graph.injectValue("urls", urls);
|
|
187
|
+
const result = (await graph.run());
|
|
188
|
+
if (!result?.sourceText?.text) {
|
|
189
|
+
return "";
|
|
190
|
+
}
|
|
191
|
+
const prefixPrompt = "Here is the web content that can be used as reference material for the script:";
|
|
192
|
+
return `\n\n${prefixPrompt}\n${result?.sourceText.text}`;
|
|
193
|
+
};
|
|
194
|
+
const createMulmoScriptWithInteractive = async ({ outDirPath, cacheDirPath, filename, templateName, urls }) => {
|
|
195
|
+
(0, file_1.mkdir)(outDirPath);
|
|
196
|
+
// if urls is not empty, scrape web content and reference it in the prompt
|
|
197
|
+
const webContentPrompt = urls.length > 0 ? await scrapeWebContent(urls, cacheDirPath) : "";
|
|
198
|
+
const graph = new graphai_1.GraphAI(graphData, { ...vanilla, openAIAgent: openai_agent_1.openAIAgent, textInputAgent: input_agents_1.textInputAgent, fileWriteAgent: vanilla_node_agents_1.fileWriteAgent });
|
|
199
|
+
const prompt = (0, file_1.readTemplatePrompt)(templateName);
|
|
200
|
+
graph.injectValue("messages", [
|
|
201
|
+
{
|
|
202
|
+
role: "system",
|
|
203
|
+
content: `${prompt}\n\n${interactiveClarificationPrompt}${webContentPrompt}`,
|
|
204
|
+
},
|
|
205
|
+
]);
|
|
206
|
+
graph.injectValue("outdir", outDirPath);
|
|
207
|
+
graph.injectValue("fileName", filename);
|
|
208
|
+
console.log(`${agentHeader} Hi! What topic would you like me to generate about?\n`);
|
|
209
|
+
await graph.run();
|
|
210
|
+
};
|
|
211
|
+
exports.createMulmoScriptWithInteractive = createMulmoScriptWithInteractive;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.createMulmoScriptFromUrl = void 0;
|
|
40
|
+
require("dotenv/config");
|
|
41
|
+
const graphai_1 = require("graphai");
|
|
42
|
+
const openai_agent_1 = require("@graphai/openai_agent");
|
|
43
|
+
const vanilla = __importStar(require("@graphai/vanilla"));
|
|
44
|
+
const vanilla_node_agents_1 = require("@graphai/vanilla_node_agents");
|
|
45
|
+
const browserless_agent_1 = require("@graphai/browserless_agent");
|
|
46
|
+
const validate_mulmo_script_agent_1 = __importDefault(require("../agents/validate_mulmo_script_agent"));
|
|
47
|
+
const file_1 = require("../utils/file");
|
|
48
|
+
const filters_1 = require("../utils/filters");
|
|
49
|
+
const schema_1 = require("../types/schema");
|
|
50
|
+
const graphData = {
|
|
51
|
+
version: 0.5,
|
|
52
|
+
// Execute sequentially because the free version of browserless API doesn't support concurrent execution.
|
|
53
|
+
concurrency: 1,
|
|
54
|
+
nodes: {
|
|
55
|
+
urls: {
|
|
56
|
+
value: [],
|
|
57
|
+
},
|
|
58
|
+
prompt: {
|
|
59
|
+
value: "",
|
|
60
|
+
},
|
|
61
|
+
outdir: {
|
|
62
|
+
value: "",
|
|
63
|
+
},
|
|
64
|
+
fileName: {
|
|
65
|
+
value: "",
|
|
66
|
+
},
|
|
67
|
+
// get the text content of the urls
|
|
68
|
+
fetchResults: {
|
|
69
|
+
agent: "mapAgent",
|
|
70
|
+
inputs: {
|
|
71
|
+
rows: ":urls",
|
|
72
|
+
},
|
|
73
|
+
params: {
|
|
74
|
+
compositeResult: true,
|
|
75
|
+
},
|
|
76
|
+
graph: {
|
|
77
|
+
nodes: {
|
|
78
|
+
fetcher: {
|
|
79
|
+
agent: "browserlessAgent",
|
|
80
|
+
inputs: {
|
|
81
|
+
url: ":row",
|
|
82
|
+
text_content: true,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
copyAgent: {
|
|
86
|
+
agent: "copyAgent",
|
|
87
|
+
inputs: {
|
|
88
|
+
text: '{ url: "${:row}", text: "${:fetcher.text}" }',
|
|
89
|
+
},
|
|
90
|
+
params: {
|
|
91
|
+
namedKey: "text",
|
|
92
|
+
},
|
|
93
|
+
isResult: true,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
// join the text content
|
|
99
|
+
sourceText: {
|
|
100
|
+
agent: "arrayJoinAgent",
|
|
101
|
+
inputs: {
|
|
102
|
+
array: ":fetchResults.copyAgent",
|
|
103
|
+
},
|
|
104
|
+
params: {
|
|
105
|
+
separator: ",",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
// generate the mulmo script
|
|
109
|
+
mulmoScript: {
|
|
110
|
+
agent: "nestedAgent",
|
|
111
|
+
inputs: {
|
|
112
|
+
sourceText: ":sourceText",
|
|
113
|
+
prompt: ":prompt",
|
|
114
|
+
},
|
|
115
|
+
graph: {
|
|
116
|
+
loop: {
|
|
117
|
+
// If the script is not valid and the counter is less than 3, continue the loop
|
|
118
|
+
while: ":continue",
|
|
119
|
+
},
|
|
120
|
+
nodes: {
|
|
121
|
+
counter: {
|
|
122
|
+
value: 0,
|
|
123
|
+
update: ":counter.add(1)",
|
|
124
|
+
},
|
|
125
|
+
openAIAgent: {
|
|
126
|
+
agent: "openAIAgent",
|
|
127
|
+
inputs: {
|
|
128
|
+
model: "gpt-4o",
|
|
129
|
+
system: ":prompt",
|
|
130
|
+
prompt: "Please create a script using the information from the following URLs as reference: ${:sourceText.text}",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
validateMulmoScriptAgent: {
|
|
134
|
+
agent: "validateMulmoScriptAgent",
|
|
135
|
+
inputs: {
|
|
136
|
+
text: ":openAIAgent.text.codeBlock()",
|
|
137
|
+
},
|
|
138
|
+
isResult: true,
|
|
139
|
+
},
|
|
140
|
+
continue: {
|
|
141
|
+
agent: ({ isValid, counter }) => {
|
|
142
|
+
return !isValid && counter < 3;
|
|
143
|
+
},
|
|
144
|
+
inputs: {
|
|
145
|
+
isValid: ":validateMulmoScriptAgent.isValid",
|
|
146
|
+
counter: ":counter",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
writeJSON: {
|
|
153
|
+
if: ":mulmoScript.validateMulmoScriptAgent.isValid",
|
|
154
|
+
agent: "fileWriteAgent",
|
|
155
|
+
inputs: {
|
|
156
|
+
file: "${:outdir}/${:fileName}-${@now}.json",
|
|
157
|
+
text: ":mulmoScript.validateMulmoScriptAgent.data.toJSON()",
|
|
158
|
+
},
|
|
159
|
+
isResult: true,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
const createMulmoScriptFromUrl = async ({ urls, templateName, outDirPath, filename, cacheDirPath }) => {
|
|
164
|
+
(0, file_1.mkdir)(outDirPath);
|
|
165
|
+
(0, file_1.mkdir)(cacheDirPath);
|
|
166
|
+
const parsedUrls = schema_1.urlsSchema.parse(urls);
|
|
167
|
+
const browserlessCache = (0, filters_1.browserlessCacheGenerator)(cacheDirPath);
|
|
168
|
+
const agentFilters = [
|
|
169
|
+
{
|
|
170
|
+
name: "browserlessCache",
|
|
171
|
+
agent: browserlessCache,
|
|
172
|
+
nodeIds: ["fetcher"],
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
const graph = new graphai_1.GraphAI(graphData, {
|
|
176
|
+
...vanilla,
|
|
177
|
+
openAIAgent: openai_agent_1.openAIAgent,
|
|
178
|
+
browserlessAgent: browserless_agent_1.browserlessAgent,
|
|
179
|
+
validateMulmoScriptAgent: validate_mulmo_script_agent_1.default,
|
|
180
|
+
fileWriteAgent: vanilla_node_agents_1.fileWriteAgent,
|
|
181
|
+
}, { agentFilters });
|
|
182
|
+
graph.injectValue("urls", parsedUrls);
|
|
183
|
+
graph.injectValue("prompt", (0, file_1.readTemplatePrompt)(templateName));
|
|
184
|
+
graph.injectValue("outdir", outDirPath);
|
|
185
|
+
graph.injectValue("fileName", filename);
|
|
186
|
+
await graph.run();
|
|
187
|
+
};
|
|
188
|
+
exports.createMulmoScriptFromUrl = createMulmoScriptFromUrl;
|