@mulmocast/slide 0.1.0
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 +458 -0
- package/lib/actions/bundle.d.ts +3 -0
- package/lib/actions/bundle.d.ts.map +1 -0
- package/lib/actions/bundle.js +60 -0
- package/lib/actions/bundle.js.map +1 -0
- package/lib/actions/common.d.ts +21 -0
- package/lib/actions/common.d.ts.map +1 -0
- package/lib/actions/common.js +159 -0
- package/lib/actions/common.js.map +1 -0
- package/lib/actions/movie.d.ts +3 -0
- package/lib/actions/movie.d.ts.map +1 -0
- package/lib/actions/movie.js +58 -0
- package/lib/actions/movie.js.map +1 -0
- package/lib/actions/upload.d.ts +6 -0
- package/lib/actions/upload.d.ts.map +1 -0
- package/lib/actions/upload.js +172 -0
- package/lib/actions/upload.js.map +1 -0
- package/lib/cli.d.ts +3 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +301 -0
- package/lib/cli.js.map +1 -0
- package/lib/convert/marp.d.ts +22 -0
- package/lib/convert/marp.d.ts.map +1 -0
- package/lib/convert/marp.js +375 -0
- package/lib/convert/marp.js.map +1 -0
- package/lib/convert/pdf.d.ts +14 -0
- package/lib/convert/pdf.d.ts.map +1 -0
- package/lib/convert/pdf.js +130 -0
- package/lib/convert/pdf.js.map +1 -0
- package/lib/convert/pptx.d.ts +13 -0
- package/lib/convert/pptx.d.ts.map +1 -0
- package/lib/convert/pptx.js +138 -0
- package/lib/convert/pptx.js.map +1 -0
- package/lib/utils/lang.d.ts +16 -0
- package/lib/utils/lang.d.ts.map +1 -0
- package/lib/utils/lang.js +37 -0
- package/lib/utils/lang.js.map +1 -0
- package/lib/utils/llm.d.ts +21 -0
- package/lib/utils/llm.d.ts.map +1 -0
- package/lib/utils/llm.js +200 -0
- package/lib/utils/llm.js.map +1 -0
- package/lib/utils/pdf.d.ts +37 -0
- package/lib/utils/pdf.d.ts.map +1 -0
- package/lib/utils/pdf.js +142 -0
- package/lib/utils/pdf.js.map +1 -0
- package/package.json +67 -0
- package/tools/keynote/extract.scpt +195 -0
|
@@ -0,0 +1,138 @@
|
|
|
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.convertPptx = convertPptx;
|
|
40
|
+
const ppt_png_1 = __importDefault(require("ppt-png"));
|
|
41
|
+
const node_pptx_parser_1 = __importDefault(require("node-pptx-parser"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const yargs_1 = __importDefault(require("yargs"));
|
|
45
|
+
const helpers_1 = require("yargs/helpers");
|
|
46
|
+
const lang_1 = require("../utils/lang");
|
|
47
|
+
const pdf_1 = require("../utils/pdf");
|
|
48
|
+
async function convertPptx(options) {
|
|
49
|
+
const { inputPath, lang, generateText = false } = options;
|
|
50
|
+
const resolvedLang = (0, lang_1.resolveLang)(lang);
|
|
51
|
+
const pptxFile = path.resolve(inputPath);
|
|
52
|
+
if (!fs.existsSync(pptxFile)) {
|
|
53
|
+
throw new Error(`File not found: ${pptxFile}`);
|
|
54
|
+
}
|
|
55
|
+
const basename = path.basename(pptxFile, ".pptx");
|
|
56
|
+
const outputDir = options.outputDir || path.join("scripts", basename);
|
|
57
|
+
const imagesDir = path.join(outputDir, "images");
|
|
58
|
+
// Create output directories
|
|
59
|
+
if (!fs.existsSync(outputDir)) {
|
|
60
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
console.log(`Converting ${pptxFile} to ${outputDir}/`);
|
|
63
|
+
// Convert PPTX to PDF (using ppt-png for LibreOffice conversion)
|
|
64
|
+
const converter = ppt_png_1.default.create({
|
|
65
|
+
files: [pptxFile],
|
|
66
|
+
output: outputDir + "/",
|
|
67
|
+
density: 96,
|
|
68
|
+
});
|
|
69
|
+
await converter.convert();
|
|
70
|
+
// Convert PDF to PNG images using shared utility
|
|
71
|
+
const pdfPath = path.join(outputDir, `${basename}.pdf`);
|
|
72
|
+
if (!fs.existsSync(pdfPath)) {
|
|
73
|
+
throw new Error(`PDF conversion failed: ${pdfPath} not found`);
|
|
74
|
+
}
|
|
75
|
+
console.log("Re-converting PDF with antialias...");
|
|
76
|
+
const { slideCount } = (0, pdf_1.convertPdfToImages)({
|
|
77
|
+
pdfPath,
|
|
78
|
+
imagesDir,
|
|
79
|
+
basename,
|
|
80
|
+
});
|
|
81
|
+
// Extract text from PPTX
|
|
82
|
+
const parser = new node_pptx_parser_1.default(pptxFile);
|
|
83
|
+
const textContent = await parser.extractText();
|
|
84
|
+
const slideTexts = textContent.map((slide) => slide.text.join("\n"));
|
|
85
|
+
// Build MulmoScript using shared utility
|
|
86
|
+
// Pass slideTexts as both default text and extracted text for LLM
|
|
87
|
+
const { mulmoScript } = await (0, pdf_1.buildMulmoScriptFromImages)({
|
|
88
|
+
slideCount,
|
|
89
|
+
imagesDir,
|
|
90
|
+
basename,
|
|
91
|
+
lang: resolvedLang,
|
|
92
|
+
slideTexts,
|
|
93
|
+
extractedTexts: slideTexts,
|
|
94
|
+
generateText,
|
|
95
|
+
title: basename,
|
|
96
|
+
});
|
|
97
|
+
// Write MulmoScript to JSON file
|
|
98
|
+
const jsonPath = path.join(outputDir, "mulmo_script.json");
|
|
99
|
+
(0, pdf_1.writeMulmoScript)(mulmoScript, jsonPath);
|
|
100
|
+
return {
|
|
101
|
+
mulmoScriptPath: jsonPath,
|
|
102
|
+
slideCount,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function main() {
|
|
106
|
+
const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
107
|
+
.usage("Usage: $0 <pptx-file> [options]")
|
|
108
|
+
.command("$0 <file>", "Convert PPTX to MulmoScript", (yargs) => {
|
|
109
|
+
return yargs.positional("file", {
|
|
110
|
+
describe: "PPTX file to convert",
|
|
111
|
+
type: "string",
|
|
112
|
+
demandOption: true,
|
|
113
|
+
});
|
|
114
|
+
})
|
|
115
|
+
.options({
|
|
116
|
+
...lang_1.langOption,
|
|
117
|
+
g: {
|
|
118
|
+
alias: "generate-text",
|
|
119
|
+
type: "boolean",
|
|
120
|
+
description: "Generate narration text using LLM",
|
|
121
|
+
default: false,
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
.help()
|
|
125
|
+
.parse();
|
|
126
|
+
await convertPptx({
|
|
127
|
+
inputPath: argv.file,
|
|
128
|
+
lang: argv.l,
|
|
129
|
+
generateText: argv.g,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (require.main === module) {
|
|
133
|
+
main().catch((error) => {
|
|
134
|
+
console.error("Error:", error.message);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=pptx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pptx.js","sourceRoot":"","sources":["../../src/convert/pptx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const SUPPORTED_LANGS: readonly ["en", "ja", "fr", "de"];
|
|
2
|
+
export type SupportedLang = (typeof SUPPORTED_LANGS)[number];
|
|
3
|
+
export declare const DEFAULT_LANG: SupportedLang;
|
|
4
|
+
export declare function isValidLang(lang: string): lang is SupportedLang;
|
|
5
|
+
export declare function getLangFromEnv(): SupportedLang | undefined;
|
|
6
|
+
export declare function resolveLang(cliLang?: string): SupportedLang;
|
|
7
|
+
export declare const langOption: {
|
|
8
|
+
l: {
|
|
9
|
+
alias: string;
|
|
10
|
+
type: "string";
|
|
11
|
+
choices: string[];
|
|
12
|
+
description: string;
|
|
13
|
+
default: undefined;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=lang.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.d.ts","sourceRoot":"","sources":["../../src/utils/lang.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,eAAe,mCAAoC,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,YAAY,EAAE,aAAoB,CAAC;AAEhD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,aAAa,CAE/D;AAED,wBAAgB,cAAc,IAAI,aAAa,GAAG,SAAS,CAM1D;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAM3D;AAGD,eAAO,MAAM,UAAU;;;;iBAIoB,MAAM,EAAE;;;;CAIlD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.langOption = exports.DEFAULT_LANG = exports.SUPPORTED_LANGS = void 0;
|
|
4
|
+
exports.isValidLang = isValidLang;
|
|
5
|
+
exports.getLangFromEnv = getLangFromEnv;
|
|
6
|
+
exports.resolveLang = resolveLang;
|
|
7
|
+
// Supported languages
|
|
8
|
+
exports.SUPPORTED_LANGS = ["en", "ja", "fr", "de"];
|
|
9
|
+
exports.DEFAULT_LANG = "en";
|
|
10
|
+
function isValidLang(lang) {
|
|
11
|
+
return exports.SUPPORTED_LANGS.includes(lang);
|
|
12
|
+
}
|
|
13
|
+
function getLangFromEnv() {
|
|
14
|
+
const envLang = process.env.MULMO_LANG;
|
|
15
|
+
if (envLang && isValidLang(envLang)) {
|
|
16
|
+
return envLang;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
function resolveLang(cliLang) {
|
|
21
|
+
// Priority: CLI option > environment variable > default
|
|
22
|
+
if (cliLang && isValidLang(cliLang)) {
|
|
23
|
+
return cliLang;
|
|
24
|
+
}
|
|
25
|
+
return getLangFromEnv() ?? exports.DEFAULT_LANG;
|
|
26
|
+
}
|
|
27
|
+
// Yargs option configuration for lang
|
|
28
|
+
exports.langOption = {
|
|
29
|
+
l: {
|
|
30
|
+
alias: "lang",
|
|
31
|
+
type: "string",
|
|
32
|
+
choices: exports.SUPPORTED_LANGS,
|
|
33
|
+
description: "Language for the MulmoScript",
|
|
34
|
+
default: undefined,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.js","sourceRoot":"","sources":["../../src/utils/lang.ts"],"names":[],"mappings":";;;AAMA,kCAEC;AAED,wCAMC;AAED,kCAMC;AAxBD,sBAAsB;AACT,QAAA,eAAe,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAGpD,QAAA,YAAY,GAAkB,IAAI,CAAC;AAEhD,SAAgB,WAAW,CAAC,IAAY;IACtC,OAAO,uBAAe,CAAC,QAAQ,CAAC,IAAqB,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,cAAc;IAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACvC,IAAI,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,WAAW,CAAC,OAAgB;IAC1C,wDAAwD;IACxD,IAAI,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,cAAc,EAAE,IAAI,oBAAY,CAAC;AAC1C,CAAC;AAED,sCAAsC;AACzB,QAAA,UAAU,GAAG;IACxB,CAAC,EAAE;QACD,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,QAAiB;QACvB,OAAO,EAAE,uBAAsC;QAC/C,WAAW,EAAE,8BAA8B;QAC3C,OAAO,EAAE,SAAS;KACnB;CACF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SupportedLang } from "./lang";
|
|
2
|
+
interface SlideContent {
|
|
3
|
+
index: number;
|
|
4
|
+
markdown?: string[];
|
|
5
|
+
imagePath?: string;
|
|
6
|
+
existingText?: string;
|
|
7
|
+
extractedText?: string;
|
|
8
|
+
}
|
|
9
|
+
interface GenerateTextOptions {
|
|
10
|
+
slides: SlideContent[];
|
|
11
|
+
lang: SupportedLang;
|
|
12
|
+
title?: string;
|
|
13
|
+
}
|
|
14
|
+
interface GeneratedText {
|
|
15
|
+
index: number;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function generateTextFromMarkdown(options: GenerateTextOptions): Promise<GeneratedText[]>;
|
|
19
|
+
export declare function generateTextFromImages(options: GenerateTextOptions): Promise<GeneratedText[]>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=llm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/utils/llm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAW5C,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,mBAAmB;IAC3B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAuBD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,EAAE,CAAC,CAyD1B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,EAAE,CAAC,CAuF1B"}
|
package/lib/utils/llm.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
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.generateTextFromMarkdown = generateTextFromMarkdown;
|
|
40
|
+
exports.generateTextFromImages = generateTextFromImages;
|
|
41
|
+
const openai_1 = __importDefault(require("openai"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
let openaiClient = null;
|
|
45
|
+
function getOpenAIClient() {
|
|
46
|
+
if (!openaiClient) {
|
|
47
|
+
openaiClient = new openai_1.default();
|
|
48
|
+
}
|
|
49
|
+
return openaiClient;
|
|
50
|
+
}
|
|
51
|
+
function getLanguageName(lang) {
|
|
52
|
+
const langNames = {
|
|
53
|
+
en: "English",
|
|
54
|
+
ja: "Japanese",
|
|
55
|
+
fr: "French",
|
|
56
|
+
de: "German",
|
|
57
|
+
};
|
|
58
|
+
return langNames[lang];
|
|
59
|
+
}
|
|
60
|
+
function imageToBase64(imagePath) {
|
|
61
|
+
const absolutePath = path.resolve(imagePath);
|
|
62
|
+
const imageBuffer = fs.readFileSync(absolutePath);
|
|
63
|
+
return imageBuffer.toString("base64");
|
|
64
|
+
}
|
|
65
|
+
function getImageMediaType(imagePath) {
|
|
66
|
+
const ext = path.extname(imagePath).toLowerCase();
|
|
67
|
+
return ext === ".jpg" || ext === ".jpeg" ? "image/jpeg" : "image/png";
|
|
68
|
+
}
|
|
69
|
+
async function generateTextFromMarkdown(options) {
|
|
70
|
+
const { slides, lang, title } = options;
|
|
71
|
+
const languageName = getLanguageName(lang);
|
|
72
|
+
const slideContents = slides
|
|
73
|
+
.map((s, i) => {
|
|
74
|
+
const content = s.markdown?.join("\n") || "(no content)";
|
|
75
|
+
return `--- Slide ${i + 1} ---\n${content}`;
|
|
76
|
+
})
|
|
77
|
+
.join("\n\n");
|
|
78
|
+
const targetIndices = slides.map((s) => s.index);
|
|
79
|
+
const prompt = `You are a professional presenter delivering a live presentation to an audience.
|
|
80
|
+
|
|
81
|
+
Title: ${title || "Untitled Presentation"}
|
|
82
|
+
|
|
83
|
+
Here are all the slides in the presentation:
|
|
84
|
+
|
|
85
|
+
${slideContents}
|
|
86
|
+
|
|
87
|
+
Generate narration text for slides: ${targetIndices.map((i) => i + 1).join(", ")}
|
|
88
|
+
|
|
89
|
+
Critical style requirements:
|
|
90
|
+
- Write in ${languageName}
|
|
91
|
+
- Speak directly to the audience as if presenting live - NEVER use meta-references like "this slide shows", "here we see", "このスライドでは", "ここでは", "この図は"
|
|
92
|
+
- Flow naturally from one idea to the next, as a skilled presenter would
|
|
93
|
+
- Deliver substantive, insightful explanations - not surface-level descriptions
|
|
94
|
+
- Explain concepts and technical terms accurately and clearly
|
|
95
|
+
- Connect ideas to help the audience understand the bigger picture
|
|
96
|
+
- Use a confident, engaging speaking style suitable for text-to-speech
|
|
97
|
+
- Don't just read bullet points - explain what they mean and why they matter
|
|
98
|
+
|
|
99
|
+
Bad example: "このスライドでは、3つのポイントを説明します。"
|
|
100
|
+
Good example: "効果的な実装には3つの重要な要素があります。まず..."
|
|
101
|
+
|
|
102
|
+
Respond in JSON format:
|
|
103
|
+
{
|
|
104
|
+
"slides": [
|
|
105
|
+
{"index": <0-based index>, "text": "<narration text>"},
|
|
106
|
+
...
|
|
107
|
+
]
|
|
108
|
+
}`;
|
|
109
|
+
const response = await getOpenAIClient().chat.completions.create({
|
|
110
|
+
model: "gpt-4o",
|
|
111
|
+
messages: [{ role: "user", content: prompt }],
|
|
112
|
+
response_format: { type: "json_object" },
|
|
113
|
+
});
|
|
114
|
+
const content = response.choices[0]?.message?.content;
|
|
115
|
+
if (!content) {
|
|
116
|
+
throw new Error("No response from OpenAI");
|
|
117
|
+
}
|
|
118
|
+
const result = JSON.parse(content);
|
|
119
|
+
return result.slides;
|
|
120
|
+
}
|
|
121
|
+
async function generateTextFromImages(options) {
|
|
122
|
+
const { slides, lang, title } = options;
|
|
123
|
+
const languageName = getLanguageName(lang);
|
|
124
|
+
const targetIndices = slides.map((s) => s.index);
|
|
125
|
+
// Check if any slides have extracted text
|
|
126
|
+
const hasExtractedText = slides.some((s) => s.extractedText && s.extractedText.trim().length > 0);
|
|
127
|
+
const extractedTextSection = hasExtractedText
|
|
128
|
+
? `
|
|
129
|
+
Additionally, here is the extracted text from each slide for reference. Use this to understand technical details, proper nouns, and specific information that may not be clearly visible in the images:
|
|
130
|
+
|
|
131
|
+
${slides
|
|
132
|
+
.map((s, i) => {
|
|
133
|
+
const text = s.extractedText?.trim() || "(no text extracted)";
|
|
134
|
+
return `--- Slide ${i + 1} Text ---\n${text}`;
|
|
135
|
+
})
|
|
136
|
+
.join("\n\n")}
|
|
137
|
+
`
|
|
138
|
+
: "";
|
|
139
|
+
const prompt = `You are a professional presenter delivering a live presentation to an audience.
|
|
140
|
+
|
|
141
|
+
Title: ${title || "Untitled Presentation"}
|
|
142
|
+
|
|
143
|
+
I'm showing you all slides in the presentation as images.${extractedTextSection}
|
|
144
|
+
|
|
145
|
+
Generate narration text for slides: ${targetIndices.map((i) => i + 1).join(", ")}
|
|
146
|
+
|
|
147
|
+
Critical style requirements:
|
|
148
|
+
- Write in ${languageName}
|
|
149
|
+
- Speak directly to the audience as if presenting live - NEVER use meta-references like "this slide shows", "here we see", "このスライドでは", "ここでは", "この図は"
|
|
150
|
+
- Flow naturally from one idea to the next, as a skilled presenter would
|
|
151
|
+
- Deliver substantive, insightful explanations - not surface-level descriptions
|
|
152
|
+
- Explain concepts, data, and technical terms accurately and clearly
|
|
153
|
+
- Connect ideas to help the audience understand the bigger picture
|
|
154
|
+
- Use a confident, engaging speaking style suitable for text-to-speech
|
|
155
|
+
- When discussing charts, data, or diagrams, explain what the information means and why it matters - don't just describe what's visible
|
|
156
|
+
- Use the extracted text to ensure accuracy of technical terms, names, numbers, and specific details
|
|
157
|
+
|
|
158
|
+
Bad example: "このスライドでは、AIロボティクスの市場動向を示しています。"
|
|
159
|
+
Good example: "AIロボティクス市場は急速に拡大しており、2030年には60兆円規模に達すると予測されています。"
|
|
160
|
+
|
|
161
|
+
Respond in JSON format:
|
|
162
|
+
{
|
|
163
|
+
"slides": [
|
|
164
|
+
{"index": <0-based index>, "text": "<narration text>"},
|
|
165
|
+
...
|
|
166
|
+
]
|
|
167
|
+
}`;
|
|
168
|
+
const slideImageContents = slides
|
|
169
|
+
.filter((slide) => slide.imagePath && fs.existsSync(slide.imagePath))
|
|
170
|
+
.flatMap((slide, i) => {
|
|
171
|
+
const base64 = imageToBase64(slide.imagePath);
|
|
172
|
+
const mediaType = getImageMediaType(slide.imagePath);
|
|
173
|
+
return [
|
|
174
|
+
{ type: "text", text: `--- Slide ${i + 1} ---` },
|
|
175
|
+
{
|
|
176
|
+
type: "image_url",
|
|
177
|
+
image_url: {
|
|
178
|
+
url: `data:${mediaType};base64,${base64}`,
|
|
179
|
+
detail: "high",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
});
|
|
184
|
+
const imageContents = [
|
|
185
|
+
{ type: "text", text: prompt },
|
|
186
|
+
...slideImageContents,
|
|
187
|
+
];
|
|
188
|
+
const response = await getOpenAIClient().chat.completions.create({
|
|
189
|
+
model: "gpt-4o",
|
|
190
|
+
messages: [{ role: "user", content: imageContents }],
|
|
191
|
+
response_format: { type: "json_object" },
|
|
192
|
+
});
|
|
193
|
+
const content = response.choices[0]?.message?.content;
|
|
194
|
+
if (!content) {
|
|
195
|
+
throw new Error("No response from OpenAI");
|
|
196
|
+
}
|
|
197
|
+
const result = JSON.parse(content);
|
|
198
|
+
return result.slides;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=llm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/utils/llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mulmoScriptSchema, type MulmoBeat } from "mulmocast";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
import type { SupportedLang } from "./lang";
|
|
4
|
+
type MulmoScriptOutput = z.output<typeof mulmoScriptSchema>;
|
|
5
|
+
export interface ExtractedPageText {
|
|
6
|
+
pageNumber: number;
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function extractTextFromPdf(pdfPath: string): Promise<ExtractedPageText[]>;
|
|
10
|
+
export interface PdfToImagesOptions {
|
|
11
|
+
pdfPath: string;
|
|
12
|
+
imagesDir: string;
|
|
13
|
+
basename: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PdfToImagesResult {
|
|
16
|
+
imageFiles: string[];
|
|
17
|
+
slideCount: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function convertPdfToImages(options: PdfToImagesOptions): PdfToImagesResult;
|
|
20
|
+
export interface BuildMulmoScriptOptions {
|
|
21
|
+
slideCount: number;
|
|
22
|
+
imagesDir: string;
|
|
23
|
+
basename: string;
|
|
24
|
+
lang: SupportedLang;
|
|
25
|
+
slideTexts?: string[];
|
|
26
|
+
extractedTexts?: string[];
|
|
27
|
+
generateText?: boolean;
|
|
28
|
+
title?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface BuildMulmoScriptResult {
|
|
31
|
+
mulmoScript: MulmoScriptOutput;
|
|
32
|
+
beats: MulmoBeat[];
|
|
33
|
+
}
|
|
34
|
+
export declare function buildMulmoScriptFromImages(options: BuildMulmoScriptOptions): Promise<BuildMulmoScriptResult>;
|
|
35
|
+
export declare function writeMulmoScript(mulmoScript: MulmoScriptOutput, outputPath: string): void;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=pdf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../src/utils/pdf.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAI5C,KAAK,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAetF;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAkCjF;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CAqEjC;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAIzF"}
|
package/lib/utils/pdf.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
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.extractTextFromPdf = extractTextFromPdf;
|
|
37
|
+
exports.convertPdfToImages = convertPdfToImages;
|
|
38
|
+
exports.buildMulmoScriptFromImages = buildMulmoScriptFromImages;
|
|
39
|
+
exports.writeMulmoScript = writeMulmoScript;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const mulmocast_1 = require("mulmocast");
|
|
44
|
+
const llm_1 = require("./llm");
|
|
45
|
+
async function extractTextFromPdf(pdfPath) {
|
|
46
|
+
const { PDFParse } = await Promise.resolve().then(() => __importStar(require("pdf-parse")));
|
|
47
|
+
const dataBuffer = fs.readFileSync(pdfPath);
|
|
48
|
+
const uint8Array = new Uint8Array(dataBuffer);
|
|
49
|
+
const parser = new PDFParse(uint8Array);
|
|
50
|
+
await parser.load();
|
|
51
|
+
const textResult = await parser.getText();
|
|
52
|
+
// textResult.pages is an array of { text: string, num: number }
|
|
53
|
+
return textResult.pages.map((page) => ({
|
|
54
|
+
pageNumber: page.num - 1, // Convert to 0-based index
|
|
55
|
+
text: page.text.trim(),
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
function convertPdfToImages(options) {
|
|
59
|
+
const { pdfPath, imagesDir, basename } = options;
|
|
60
|
+
if (!fs.existsSync(pdfPath)) {
|
|
61
|
+
throw new Error(`PDF not found: ${pdfPath}`);
|
|
62
|
+
}
|
|
63
|
+
// Create images directory if it doesn't exist
|
|
64
|
+
if (!fs.existsSync(imagesDir)) {
|
|
65
|
+
fs.mkdirSync(imagesDir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
// Delete old PNGs from images directory
|
|
68
|
+
const oldPngs = fs.readdirSync(imagesDir).filter((f) => f.endsWith(".png"));
|
|
69
|
+
oldPngs.forEach((f) => fs.unlinkSync(path.join(imagesDir, f)));
|
|
70
|
+
// Convert with ImageMagick (better antialias) to images/ directory
|
|
71
|
+
// Use 'magick' on macOS/Windows (ImageMagick 7), 'convert' on Linux (ImageMagick 6)
|
|
72
|
+
const magickCmd = process.platform === "linux" ? "convert" : "magick";
|
|
73
|
+
(0, child_process_1.execSync)(`${magickCmd} -density 300 -antialias "${pdfPath}" -background white -alpha remove -quality 95 "${imagesDir}/${basename}-%d.png"`, { stdio: "inherit" });
|
|
74
|
+
// Count generated images
|
|
75
|
+
const imageFiles = fs
|
|
76
|
+
.readdirSync(imagesDir)
|
|
77
|
+
.filter((f) => f.startsWith(`${basename}-`) && f.endsWith(".png"))
|
|
78
|
+
.sort();
|
|
79
|
+
return {
|
|
80
|
+
imageFiles,
|
|
81
|
+
slideCount: imageFiles.length,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async function buildMulmoScriptFromImages(options) {
|
|
85
|
+
const { slideCount, imagesDir, basename, lang, slideTexts = [], extractedTexts = [], generateText = false, title, } = options;
|
|
86
|
+
const beats = Array.from({ length: slideCount }, (_, index) => {
|
|
87
|
+
const imagePath = `./images/${basename}-${index}.png`;
|
|
88
|
+
const text = slideTexts[index] || "";
|
|
89
|
+
return {
|
|
90
|
+
text,
|
|
91
|
+
image: {
|
|
92
|
+
type: "image",
|
|
93
|
+
source: {
|
|
94
|
+
kind: "path",
|
|
95
|
+
path: imagePath,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
// Generate text using LLM if requested
|
|
101
|
+
if (generateText) {
|
|
102
|
+
console.log("Generating narration text with LLM...");
|
|
103
|
+
const slides = beats.map((_, index) => ({
|
|
104
|
+
index,
|
|
105
|
+
imagePath: path.join(imagesDir, `${basename}-${index}.png`),
|
|
106
|
+
existingText: "",
|
|
107
|
+
extractedText: extractedTexts[index] || "",
|
|
108
|
+
}));
|
|
109
|
+
const generatedTexts = await (0, llm_1.generateTextFromImages)({
|
|
110
|
+
slides,
|
|
111
|
+
lang,
|
|
112
|
+
title: title || basename,
|
|
113
|
+
});
|
|
114
|
+
generatedTexts.forEach((generated) => {
|
|
115
|
+
if (beats[generated.index]) {
|
|
116
|
+
beats[generated.index].text = generated.text;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
console.log(`Generated text for ${generatedTexts.length} slides`);
|
|
120
|
+
}
|
|
121
|
+
const mulmoScript = {
|
|
122
|
+
$mulmocast: {
|
|
123
|
+
version: "1.1",
|
|
124
|
+
},
|
|
125
|
+
lang,
|
|
126
|
+
beats,
|
|
127
|
+
};
|
|
128
|
+
// Validate mulmoScript
|
|
129
|
+
const result = mulmocast_1.mulmoScriptSchema.safeParse(mulmoScript);
|
|
130
|
+
if (!result.success) {
|
|
131
|
+
console.error("MulmoScript validation failed:");
|
|
132
|
+
console.error(result.error.format());
|
|
133
|
+
throw new Error("Invalid MulmoScript generated");
|
|
134
|
+
}
|
|
135
|
+
return { mulmoScript: result.data, beats };
|
|
136
|
+
}
|
|
137
|
+
function writeMulmoScript(mulmoScript, outputPath) {
|
|
138
|
+
fs.writeFileSync(outputPath, JSON.stringify(mulmoScript, null, 2));
|
|
139
|
+
console.log(`Generated: ${outputPath}`);
|
|
140
|
+
console.log(`Total slides: ${mulmoScript.beats.length}`);
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=pdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/utils/pdf.ts"],"names":[],"mappings":"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"}
|