@lightcone-ai/daemon 0.15.44 → 0.15.46
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/package.json +1 -1
- package/src/chat-bridge.js +14 -0
- package/src/tools/render-html-to-image.js +58 -0
package/package.json
CHANGED
package/src/chat-bridge.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { runRecordUrlNarrationTool } from './record-url-narration-tool.js';
|
|
23
23
|
import { runSubmitToLibraryTool } from './submit-to-library-tool.js';
|
|
24
24
|
import { runRenderTextToImageTool } from './tools/render-text-to-image.js';
|
|
25
|
+
import { runRenderHtmlToImageTool } from './tools/render-html-to-image.js';
|
|
25
26
|
import { runSynthesisTtsTool } from './tools/synthesize-tts.js';
|
|
26
27
|
import { runComposeVideoV2Tool } from './tools/compose-video-v2.js';
|
|
27
28
|
import { runTakePageScreenshotTool } from './tools/take-page-screenshot.js';
|
|
@@ -1421,6 +1422,19 @@ server.tool('render_text_to_image',
|
|
|
1421
1422
|
async (args) => runRenderTextToImageTool(args)
|
|
1422
1423
|
);
|
|
1423
1424
|
|
|
1425
|
+
// ── render_html_to_image ───────────────────────────────────────────────────────
|
|
1426
|
+
server.tool('render_html_to_image',
|
|
1427
|
+
'Render a raw HTML string to a PNG image by navigating to it as a local file:// page. Unlike evaluate_script+document.write on about:blank, this preserves file:// origin so <img src="file:///..."> references load correctly. Returns the output image path.',
|
|
1428
|
+
{
|
|
1429
|
+
html: z.string().describe('Full HTML document to render (including <!doctype>, <html>, <head>, <body>).'),
|
|
1430
|
+
output_path: z.string().optional().describe('Absolute path to save the PNG. Auto-generated in /tmp if omitted.'),
|
|
1431
|
+
viewport_width: z.number().optional().describe('Viewport width in pixels. Default 1080.'),
|
|
1432
|
+
viewport_height: z.number().optional().describe('Viewport height in pixels. Default 1920.'),
|
|
1433
|
+
wait_until: z.enum(['load', 'networkidle', 'domcontentloaded']).optional().describe('Navigation wait condition. Default load.'),
|
|
1434
|
+
},
|
|
1435
|
+
async (args) => runRenderHtmlToImageTool(args)
|
|
1436
|
+
);
|
|
1437
|
+
|
|
1424
1438
|
// ── synthesize_tts ─────────────────────────────────────────────────────────────
|
|
1425
1439
|
server.tool('synthesize_tts',
|
|
1426
1440
|
'Convert text to speech using the workspace MiniMax TTS credential. Returns a local mp3 file path and duration. Use this to generate narration audio for individual video segments.',
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
function toolText(text) {
|
|
7
|
+
return { content: [{ type: 'text', text }] };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function toolError(text) {
|
|
11
|
+
return { isError: true, content: [{ type: 'text', text }] };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function launchBrowser() {
|
|
15
|
+
let playwright;
|
|
16
|
+
try {
|
|
17
|
+
playwright = await import('playwright');
|
|
18
|
+
} catch {
|
|
19
|
+
throw new Error('playwright_import_failed: run npm install playwright');
|
|
20
|
+
}
|
|
21
|
+
return playwright.chromium.launch({ headless: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function runRenderHtmlToImageTool({ html, output_path, viewport_width, viewport_height, wait_until }) {
|
|
25
|
+
const normalizedHtml = String(html ?? '').trim();
|
|
26
|
+
if (!normalizedHtml) return toolError('html is required and must not be empty.');
|
|
27
|
+
|
|
28
|
+
const vw = Number(viewport_width ?? 1080);
|
|
29
|
+
const vh = Number(viewport_height ?? 1920);
|
|
30
|
+
const waitUntil = String(wait_until ?? 'load');
|
|
31
|
+
|
|
32
|
+
const tmpDir = path.join(os.tmpdir(), 'lightcone-html-render');
|
|
33
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
34
|
+
|
|
35
|
+
const htmlFile = path.join(tmpDir, `render-${randomUUID().slice(0, 8)}.html`);
|
|
36
|
+
writeFileSync(htmlFile, normalizedHtml, 'utf-8');
|
|
37
|
+
|
|
38
|
+
const outPath = output_path
|
|
39
|
+
? String(output_path)
|
|
40
|
+
: path.join(tmpDir, `render-${randomUUID().slice(0, 8)}.png`);
|
|
41
|
+
|
|
42
|
+
const browser = await launchBrowser();
|
|
43
|
+
try {
|
|
44
|
+
const page = await browser.newPage();
|
|
45
|
+
await page.setViewportSize({ width: vw, height: vh });
|
|
46
|
+
// Navigate to file:// so local file:// image src attributes load correctly
|
|
47
|
+
await page.goto(`file://${htmlFile}`, { waitUntil, timeout: 30000 });
|
|
48
|
+
await page.screenshot({ path: outPath });
|
|
49
|
+
await page.close();
|
|
50
|
+
return toolText([
|
|
51
|
+
'render_html_to_image completed.',
|
|
52
|
+
`path=${outPath}`,
|
|
53
|
+
`viewport=${vw}x${vh}`,
|
|
54
|
+
].join('\n'));
|
|
55
|
+
} finally {
|
|
56
|
+
await browser.close();
|
|
57
|
+
}
|
|
58
|
+
}
|