Initial version of the working CI pipeline

Added mocha based unit tests for each module
Did a bit of cleanup in the modules to remove debug console.log calls
Removed the Progress bar in the extractor and the library requirement
Promisified the gemini module to make sure it returns the path as a promise instead of just on the cli
Fixed gitignore so that it now only ignores the content int the storage directories, and not the whole directories
Added neetingReport.json for the LLMs to use
This commit is contained in:
2025-12-09 22:07:43 +01:00
parent 037d29e656
commit faee605f12
14 changed files with 770 additions and 122 deletions
+2
View File
@@ -19,4 +19,6 @@ job-install:
job-test:
stage: test
script:
- echo "ASSEMBLYAI_API_KEY=$apikey_assembly" > .env
- echo "GOOGLE_API_KEY=$apikey_gemini" >> .env
- npm test
+1 -1
View File
@@ -185,7 +185,7 @@ electron.ipcMain.on("file_submit", async (event, args) => {
for (let i = 0; i < args.document.styles.length; i++) {
console.log(`\n\n Running the LLM for Document Style ${i+1}`);
await mapFunctions.get("module-handler").function(args.document.module, {inputTranscriptPath: transcriptpath, documentTypePath: "/Users/mikehughes/PROJ/video2document/storage/documentType/meetingReport.json", language: "en"}).then(resp => {
await mapFunctions.get("module-handler").function(args.document.module, {inputTranscriptPath: transcriptpath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
console.log(resp);
transcriptpath = resp
curstep++
+456 -10
View File
@@ -12,12 +12,12 @@
"@google/genai": "^1.30.0",
"@types/axios": "^0.9.36",
"axios": "^1.13.2",
"cli-progress": "^3.12.0",
"dotenv": "^17.2.3",
"electron": "^39.1.1",
"express": "^5.1.0",
"ffmpeg-static": "^5.2.0",
"fluent-ffmpeg": "^2.1.3"
"fluent-ffmpeg": "^2.1.3",
"mocha": "^11.7.5"
},
"devDependencies": {
"@types/cli-progress": "^3.11.6",
@@ -397,6 +397,11 @@
"dev": true,
"license": "MIT"
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/async": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
@@ -488,6 +493,11 @@
"balanced-match": "^1.0.0"
}
},
"node_modules/browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
},
"node_modules/buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@@ -567,22 +577,118 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
"license": "Apache-2.0"
},
"node_modules/cli-progress": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz",
"integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==",
"license": "MIT",
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"string-width": "^4.2.3"
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=4"
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chalk/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/cliui/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/cliui/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/clone-response": {
@@ -732,6 +838,17 @@
}
}
},
"node_modules/decamelize": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
@@ -981,6 +1098,14 @@
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
"optional": true
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -990,7 +1115,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"optional": true,
"engines": {
"node": ">=10"
},
@@ -1133,6 +1257,29 @@
"node": ">= 0.8"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"bin": {
"flat": "cli.js"
}
},
"node_modules/fluent-ffmpeg": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz",
@@ -1309,6 +1456,14 @@
"node": ">=18"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -1499,6 +1654,14 @@
"node": ">=18"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
@@ -1547,6 +1710,14 @@
"node": ">= 0.4"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"bin": {
"he": "bin/he"
}
},
"node_modules/http-cache-semantics": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
@@ -1654,11 +1825,38 @@
"node": ">=8"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"engines": {
"node": ">=8"
}
},
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
},
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1679,6 +1877,17 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
@@ -1734,6 +1943,35 @@
"json-buffer": "3.0.1"
}
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dependencies": {
"p-locate": "^5.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dependencies": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lowercase-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
@@ -1842,6 +2080,49 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mocha": {
"version": "11.7.5",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz",
"integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==",
"dependencies": {
"browser-stdout": "^1.3.1",
"chokidar": "^4.0.1",
"debug": "^4.3.5",
"diff": "^7.0.0",
"escape-string-regexp": "^4.0.0",
"find-up": "^5.0.0",
"glob": "^10.4.5",
"he": "^1.2.0",
"is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"log-symbols": "^4.1.0",
"minimatch": "^9.0.5",
"ms": "^2.1.3",
"picocolors": "^1.1.1",
"serialize-javascript": "^6.0.2",
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
"workerpool": "^9.2.0",
"yargs": "^17.7.2",
"yargs-parser": "^21.1.1",
"yargs-unparser": "^2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
"mocha": "bin/mocha.js"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/mocha/node_modules/diff": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
"integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -1950,6 +2231,34 @@
"node": ">=8"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dependencies": {
"p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -1968,6 +2277,14 @@
"node": ">= 0.8"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"engines": {
"node": ">=8"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -2005,6 +2322,11 @@
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -2065,6 +2387,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -2101,6 +2431,26 @@
"node": ">= 6"
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"engines": {
"node": ">= 14.18.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -2238,6 +2588,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/serve-static": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
@@ -2430,6 +2788,17 @@
"node": ">=8"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sumchecker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
@@ -2441,6 +2810,20 @@
"node": ">= 8.0"
}
},
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -2601,6 +2984,11 @@
"which": "bin/which"
}
},
"node_modules/workerpool": {
"version": "9.3.4",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz",
"integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg=="
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@@ -2719,6 +3107,53 @@
}
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"engines": {
"node": ">=10"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-unparser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dependencies": {
"camelcase": "^6.0.0",
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
@@ -2737,6 +3172,17 @@
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
-1
View File
@@ -3,7 +3,6 @@
"@google/genai": "^1.30.0",
"@types/axios": "^0.9.36",
"axios": "^1.13.2",
"cli-progress": "^3.12.0",
"dotenv": "^17.2.3",
"electron": "^39.1.1",
"express": "^5.1.0",
+1 -1
View File
@@ -11,7 +11,7 @@ config = require("./config/config")
ffmpegPath = require('ffmpeg-static');
ffmpeg = require('fluent-ffmpeg');
path = require('path');
cliProgress = require('cli-progress');
// cliProgress = require('cli-progress');
// { app, BrowserWindow, ipcMain, dialog } = require('electron');
+5 -22
View File
@@ -24,17 +24,11 @@ module.exports = {
outputType: String // Audio file output format
}
*/
let progressBar = new cliProgress.SingleBar({
format: 'Processing |{bar}| {percentage}% | {timemark}',
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
hideCursor: true
});
try {
return new Promise((resolve, reject) => {
this.extractAudioFromVideo(parameter.inputVideoPath, progressBar, parameter.outputType)
this.extractAudioFromVideo(parameter.inputVideoPath, parameter.outputType)
.then((resp) => resolve(resp))
.catch((err) => console.error(err));
.catch((err) => {reject(err)});
})
} catch (error) {
console.log(parameter.outputType);
@@ -52,7 +46,7 @@ module.exports = {
* - Shows CLI progress bar
* - Handles errors gracefully (without errors)
*/
extractAudioFromVideo: async function (videoFilePath, progressBar, outputType){
extractAudioFromVideo: async function (videoFilePath, outputType){
let inputVideoName = path.basename(videoFilePath, path.extname(videoFilePath));
let outputAudioPath = path.join(outputDir, `${inputVideoName}.${outputType}`);
@@ -63,28 +57,17 @@ module.exports = {
// .audioCodec('pcm_s16le')
.audioChannels(1)
.audioFrequency(16000)
// .setFfmpegPath("./ffmpeg.exe")
.on('progress', (progress) => {
if (!progressBar.isActive) progressBar.start(100, 0, { timemark: '00:00:00' });
if (progress.percent) {
progressBar.update(progress.percent, { timemark: progress.timemark });
}
})
.on('end', () => {
progressBar.update(100, { timemark: 'done' });
progressBar.stop();
console.log(`Extraction completed: ${outputAudioPath}`);
resolve(outputAudioPath);
})
.on('error', (err) => {
progressBar.stop();
console.error(`failed_audio_extraction on type ${outputType}: ${err.message}`);
// console.error(`failed_audio_extraction on type ${outputType}: ${err.message}`);
reject(err);
})
.save(outputAudioPath);
} catch (error) {
console.log();
// console.log(error);
}
});
}
@@ -21,30 +21,36 @@ module.exports = {
const raw = fs.readFileSync(args.jsonPath, "utf-8");
inputJson = JSON.parse(raw);
} catch (e) {
console.error("Failed to load JSON from file:", e);
return { error: "Could not read JSON from file path." };
// console.error("Failed to load JSON from file:", e);
reject(e)
return
}
}
// JSON parsen
if (typeof args === "string") {
try {
await new Promise((res) => {
await new Promise((res, rej) => {
fs.readFile(args, 'utf8', function (err, data) {
if (err) throw err;
if (err){
rej(err)
return
}
inputJson = JSON.parse(data);
res()
});
})
} catch (e) {
console.log("Invalid JSON in summarize-transcription");
console.log(e)
return { error: "Invalid JSON" };
// console.log("Invalid JSON in summarize-transcription");
// console.log(e)
reject(e)
return
}
}
const words = inputJson.words;
if (!Array.isArray(words)) {
return { error: "No words Array found" };
reject("No words Array found")
return
}
const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ?
@@ -136,11 +142,11 @@ module.exports = {
const txtPath = path.join(outputDir, "transcription_result.txt");
fs.writeFileSync(txtPath, output.join("\n"), "utf-8");
console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
// console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
resolve(jsonPath);
} catch (err) {
console.error("Error saving Summary:", err);
// console.error("Error saving Summary:", err);
reject(err);
}
})
@@ -32,29 +32,35 @@ module.exports = {
inputJson = JSON.parse(raw);
} catch (e) {
console.error("Failed to load JSON from file:", e);
return { error: "Could not read JSON from file path." };
reject("Could not read JSON from file path.")
return
}
}
// JSON parsen
if (typeof args === "string") {
try {
await new Promise((res) => {
fs.readFile(args, 'utf8', function (err, data) {
if (err) throw err;
inputJson = JSON.parse(data);
res()
});
})
} catch (e) {
console.log("Invalid JSON in summarize-transcription");
console.log(e)
return { error: "Invalid JSON" };
}
if (typeof args === "string") {
try {
await new Promise((res, rej) => {
fs.readFile(args, 'utf8', function (err, data) {
if (err){
rej(err)
return
}
inputJson = JSON.parse(data);
res()
});
})
} catch (e) {
// console.log("Invalid JSON in summarize-transcription");
// console.log(e)
reject(e)
return
}
}
const words = inputJson.words;
if (!Array.isArray(words)) {
return { error: "No words Array found" };
reject("No words Array found")
return;
}
const ENDINGS = [".", "!", "?"]; // '...' auch als Satzende ?
@@ -70,7 +76,7 @@ module.exports = {
if (!currentSpeaker) currentSpeaker = w.speaker;
if (startTime === null) startTime = w.start;
endTime = w.end;
//speaker changing
if (currentSpeaker !== w.speaker && currentSentence) {
result.push({
@@ -132,10 +138,10 @@ module.exports = {
const txtPath = path.join(outputDir, `${filename}-${new Date().getTime()}.txt`);
fs.writeFileSync(txtPath, output.join("\n"), "utf-8");
console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
// console.log(`Summary successfully saved:\n- ${jsonPath}\n- ${txtPath}`);
resolve(jsonPath);
} catch (err) {
console.error("Error saving Summary:", err);
// console.error("Error saving Summary:", err);
reject(err);
}
})
+56 -48
View File
@@ -16,61 +16,69 @@ module.exports = {
description: "Generates documents using Google Gemini LLM",
async function(parameter) {
try {
console.log("Gemini LLM module invoked with parameters:", parameter);
return new Promise(async (resolve, reject) => {
try {
// console.log("Gemini LLM module invoked with parameters:", parameter);
await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
parameter.inputTranscriptPath, // Path to input transcript file
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
parameter.language // Language for the document which is chosen in the front end by the user
);
resolve(await this.createDocumentFromTranscript( //Call the function to create document with transcript, document type and language
parameter.inputTranscriptPath, // Path to input transcript file
parameter.documentTypePath, // Path to document type file which is chosen in the front end by the user
parameter.language // Language for the document which is chosen in the front end by the user
));
} catch (error) {
// console.error("Error in Gemini LLM module:", error);
reject(error)
}
})
} catch (error) {
console.error("Error in Gemini LLM module:", error);
}
},
createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { // default language is English
try {
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); //read transcript file from Path
const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); //read document type from Path
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; //combine doc type, language and transcript - Change prompt here if needed
return new Promise(async(resolve, reject) => {
try {
const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); //read transcript file from Path
const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); //read document type from Path
const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; //combine doc type, language and transcript - Change prompt here if needed
// --- REST CALL ---
const response = await fetch(`${GEMINI_URL}?key=${GEMINI_API_KEY}`, { //safe model response in variable
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
contents: [
{
parts: [
{ text: promptText } // Input prompt for content generation
]
}
]
})
});
// --- REST CALL ---
const response = await fetch(`${GEMINI_URL}?key=${GEMINI_API_KEY}`, { //safe model response in variable
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
contents: [
{
parts: [
{ text: promptText } // Input prompt for content generation
]
}
]
})
});
if (!response.ok) { //ok is true when a responce was successfull
const text = await response.text();
throw new Error(`Gemini API error (${response.status}): ${text}`);
if (!response.ok) { //ok is true when a responce was successfull
const text = await response.text();
throw new Error(`Gemini API error (${response.status}): ${text}`);
}
const data = await response.json();
// Get generated text from response or default to empty string (if null)
const output = data?.candidates?.[0]?.content?.parts?.[0]?.text || "";
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
// console.log(inputTranscriptName);
const outPath = path.join(outputDir, `${inputTranscriptName}.md`); // Output file path & name to make naming dynamic. Pulled from input transcript name
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
// console.log("Generated document written to:", outPath);
resolve(outPath)
} catch (error) {
// console.error("Error generating Gemini content:", error);
reject(error)
}
const data = await response.json();
// Get generated text from response or default to empty string (if null)
const output = data?.candidates?.[0]?.content?.parts?.[0]?.text || "";
let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); // Name for the output file
console.log(inputTranscriptName);
const outPath = path.join(outputDir, `${inputTranscriptName}.md`); // Output file path & name to make naming dynamic. Pulled from input transcript name
fs.writeFileSync(outPath, output, "utf8"); // Write output to file
console.log("Generated document written to:", outPath);
} catch (error) {
console.error("Error generating Gemini content:", error);
}
})
}
};
@@ -78,7 +78,7 @@ function saveTranscript(transcript, sessionId) {
const outputPath = path.join(outputDir, `${sessionId}.json`);
fs.writeFileSync(outputPath, JSON.stringify(transcript, null, 2));
console.log(`Transcript saved: ${outputPath}`);
// console.log(`Transcript saved: ${outputPath}`);
return outputPath;
}
@@ -116,8 +116,9 @@ module.exports = {
resolve(saveTranscript(transcript, sessionId));
} catch (error) {
console.error('Transcription error:', error.message);
// console.error('Transcription error:', error.message);
reject(error);
return
}
})
}
+1
View File
@@ -1,3 +1,4 @@
module.exports = {
name:"Startup_function",
async function(){
+35
View File
@@ -0,0 +1,35 @@
{
"FORMAT": "markdown",
"GOAL":"Generate a structured meeting report (Markdown). **Output ONLY:** final .md. No meta.",
"STRUCTURE": {
"titlepage": ["title","date","start","end","duration","location","host","participants"],
"toc": "[section](#anchor) — HH:MM:SS",
"section": {
"h2": "<topic> — HH:MM:SS",
"summary": "1 sentence",
"key_points": "<=5 bullets, quotes optional",
"decisions": "list: text | owner | due",
"actions": "table: id | task | owner | due | status"
},
"exec_summary": "3 short sentences",
"consolidated": ["decisions", "actions"],
"appendix": "optional"
},
"STYLE": {
"tone": "neutral, concise",
"ts_format": "HH:MM:SS",
"no_meta": true
},
"PROCESS": {
"timestamps": "use if present; else estimate minimal",
"speakers": "use labels; else Speaker X",
"long_transcripts": "chunk → summarize → merge",
"unclear": "UNKLAR:<reason>"
},
"JSON_OUTPUT_OPTIONAL": true,
"PROMPT_SNIPPET": "Generate meeting report in markdown using STRUCTURE and STYLE. Output only the report."
}
+169 -8
View File
@@ -1,9 +1,170 @@
describe('Just a little test', () => {
it('1 should be 1', (done) => {
if(1 == 1){
done()
}else{
throw Error("something went terribly wrong")
}
// DO NOT TOUCH THIS
require("../../requires.js")
mapFunctions = new Map()
// Loading the Function Map
var path = `${mainDir}/services/modules`
var folders = fs.readdirSync(path).filter(function (file) {
return fs.statSync(path+'/'+file).isDirectory();
});
folders.forEach(element => {
var commandFiles = fs.readdirSync(`${path}/${element}`).filter(file => file.endsWith('.js') && !file.startsWith("index"));
for (const file of commandFiles) {
delete require.cache[require.resolve(`${path}/${element}/${file}`)];
const command = require(`${path}/${element}/${file}`);
mapFunctions.set(command.name, command);
}
});
// You can touch beyond this point
let audiopath
let transcriptPath
let summarizePath
let llmpath
describe("Unit Tests", function() {
describe('Audio Extraction', function () {
this.slow(1000)
this.timeout(3000)
it('Extract .mp4 to .mp3', function (done) {
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "mp3"}).then(resp => {
audiopath = resp
// console.log(resp);
done()
}).catch(err => {
throw err;
})
})
it('Extract .mp4 to .flac', function (done) {
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "flac"}).then(resp => {
// console.log(resp);
done()
}).catch(err => {
throw err;
})
})
it('Extracting to a nonexistant format', function (done) {
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: __dirname.replaceAll("\\","/")+"/testvideo.mp4", outputType: "qqq"}).then(resp => {
// console.log(resp);
done("Didnt crash")
}).catch(err => {
done()
})
})
it('Extracting from nonexistant file', function (done) {
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: "a", outputType: "mp3"}).then(resp => {
// console.log(resp);
done("Didnt crash")
}).catch(err => {
done()
})
})
it('Extracting from nonexistant file to nonexistant format', function (done) {
mapFunctions.get("extraction-video-to-audio").function({inputVideoPath: "a", outputType: "qqq"}).then(resp => {
// console.log(resp);
done("Didnt crash")
}).catch(err => {
done()
})
})
});
});
describe("Audio Transcription", function() {
this.slow(20000)
this.timeout(60000)
it('Assembly', function (done) {
mapFunctions.get("assembly").function(audiopath).then(resp => {
// console.log(resp);
transcriptPath = resp
done()
}).catch(err => {
throw err
})
})
it('Assembly Wrong file', function (done) {
mapFunctions.get("assembly").function("a").then(resp => {
// console.log(resp);
// transcriptPath = resp
done("Didnt crash")
}).catch(err => {
// console.log(err);
done()
})
})
// TODO add more Transcription Tool tests here
})
describe("Transcript Summarizer", function() {
this.slow(100)
this.timeout(1000)
it("Summarizer 1", function (done){
mapFunctions.get("summarize-transcription").function(transcriptPath).then(resp => {
done()
}).catch(err => {
throw err
})
})
it("Summarizer 1 Wrong File", function (done){
mapFunctions.get("summarize-transcription").function("a").then(resp => {
done("Didnt crash")
}).catch(err => {
done()
})
})
it("Summarizer 2 (Main)", function (done){
mapFunctions.get("summarize-transcription2").function(transcriptPath).then(resp => {
summarizePath = resp
done()
}).catch(err => {
throw err
})
})
it("Summarizer 2 (Main) Wrong File", function (done){
mapFunctions.get("summarize-transcription2").function("a").then(resp => {
done("Didnt crash")
}).catch(err => {
done()
})
})
})
describe("Large Language Model", function() {
this.slow(30000)
this.timeout(60000)
// it("ChatGPT", function (done){
// mapFunctions.get("chatgpt").function({inputTranscriptPath: summarizePath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
// done()
// }).catch(err => {
// throw err
// })
// })
it("Gemini", function (done){
mapFunctions.get("llm-gemini").function({inputTranscriptPath: summarizePath, documentTypePath: "./storage/documentType/meetingReport.json", language: "en"}).then(resp => {
llmpath = resp
done()
}).catch(err => {
throw err
})
})
})
after(function() {
console.log(`\n\n\n${audiopath} \n${transcriptPath} \n${summarizePath} \n${llmpath}`);
})
})
Binary file not shown.