diff --git a/.gitignore b/.gitignore index 8bf7970..df81756 100644 --- a/.gitignore +++ b/.gitignore @@ -963,9 +963,23 @@ app.*.symbols !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages !/dev/ci/**/Gemfile.lock -#Storage files -storage/ +# Storage files +storage/documents/* +storage/transcriptionSummaries/* +storage/transcripts/* +storage/video/* +# The inverse for the .gitkeep files, to make sure the folders are there but not the local files +!storage/documents/.gitkeep +!storage/transcriptionSummaries/.gitkeep +!storage/transcripts/.gitkeep +!storage/video/.gitkeep *.mp4 +*.webm +*.mp3 +*.mov *.wav *.flac + + +!testvideo.mp4 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5bebd17..31c1209 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,33 +1,27 @@ -workflow: - rules: - # Run the pipeline for merge requests or when committing to a branch - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH - -image: python:3.14.0 +image: node:latest stages: - - setup + # - install - test -setup_environment: - stage: setup - script: - - pip install --upgrade pip - - pip install -r requirements.txt - - echo "Dependencies installed successfully." +# job-install: +# stage: install +# script: +# - npm install +# artifacts: +# untracked: false +# when: on_success +# access: all +# expire_in: "30 days" +# paths: +# - node_modules - only: - - main - - feature/ci-pipeline-s1-09a-1 # You can add more branches if needed -test_app: + +job-test: stage: test script: - - echo "Running V2D Framework basic test..." - - python -m unittest discover || echo "No tests found." - - only: - - main - - feature/ci-pipeline-s1-09a-1 - + - npm install + - echo "ASSEMBLYAI_API_KEY=$apikey_assembly" > .env + - echo "GOOGLE_API_KEY=$apikey_gemini" >> .env + - npm test \ No newline at end of file diff --git a/main.js b/main.js index fa33871..2e80d3e 100644 --- a/main.js +++ b/main.js @@ -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++ diff --git a/package-lock.json b/package-lock.json index b11cae8..5d19254 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,18 +12,12 @@ "@google/genai": "^1.30.0", "@types/axios": "^0.9.36", "axios": "^1.13.2", - "cli-progress": "^3.12.0", - "docx": "^9.5.1", "dotenv": "^17.2.3", "electron": "^39.1.1", "express": "^5.1.0", "ffmpeg-static": "^5.2.0", "fluent-ffmpeg": "^2.1.3", - "html-to-docx": "^1.8.0", - "marked": "^17.0.1", - "open": "^11.0.0", - "pdfkit": "^0.17.2", - "puppeteer": "^24.33.0" + "mocha": "^11.7.5" }, "devDependencies": { "@types/cli-progress": "^3.11.6", @@ -565,20 +559,7 @@ "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==", - "license": "Python-2.0" - }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/async": { "version": "0.2.10", @@ -785,20 +766,10 @@ "balanced-match": "^1.0.0" } }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.1.2" - } - }, - "node_modules/browser-split": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz", - "integrity": "sha512-JhvgRb2ihQhsljNda3BI8/UcRHVzrVwo3Q+P8vDtSiyobXuFpuZ9mq+MbRGMnC22CjW3RrfXdg6j6ITX8M+7Ow==", - "license": "MIT" + "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", @@ -894,22 +865,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "license": "MIT", + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "engines": { - "node": ">=6" - } - }, - "node_modules/camelize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", - "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", - "license": "MIT", + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/caseless": { @@ -918,45 +882,101 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "license": "Apache-2.0" }, - "node_modules/chromium-bidi": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-11.0.0.tgz", - "integrity": "sha512-cM3DI+OOb89T3wO8cpPSro80Q9eKYJ7hGVXoGS3GkDPxnYSqiv+6xwpIf6XERyJ9Tdsl09hmNmY94BkgZdVekw==", - "license": "Apache-2.0", -<<<<<<< Updated upstream -======= + "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": { - "mitt": "^3.0.1", - "zod": "^3.24.1" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "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", ->>>>>>> Stashed changes - "dependencies": { - "mitt": "^3.0.1", - "zod": "^3.24.1" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "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", - "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/cliui": { @@ -1005,8 +1025,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, -<<<<<<< Updated upstream -======= "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1053,7 +1071,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, ->>>>>>> Stashed changes "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -1248,6 +1265,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", @@ -1686,7 +1714,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", "engines": { "node": ">=6" } @@ -1700,7 +1727,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" }, @@ -1924,6 +1950,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", @@ -2121,7 +2170,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2349,6 +2397,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", @@ -2407,104 +2463,12 @@ "node": ">= 0.4" } }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, - "node_modules/html-to-docx": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/html-to-docx/-/html-to-docx-1.8.0.tgz", - "integrity": "sha512-IiMBWIqXM4+cEsW//RKoonWV7DlXAJBmmKI73XJSVWTIXjGUaxSr2ck1jqzVRZknpvO8xsFnVicldKVAWrBYBA==", - "license": "MIT", - "dependencies": { - "@oozcitak/dom": "1.15.6", - "@oozcitak/util": "8.3.4", - "color-name": "^1.1.4", - "html-entities": "^2.3.3", - "html-to-vdom": "^0.7.0", - "image-size": "^1.0.0", - "image-to-base64": "^2.2.0", - "jszip": "^3.7.1", - "lodash": "^4.17.21", - "mime-types": "^2.1.35", - "nanoid": "^3.1.25", - "virtual-dom": "^2.1.1", - "xmlbuilder2": "2.1.2" - } - }, - "node_modules/html-to-docx/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/html-to-docx/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/html-to-docx/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "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": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/html-to-vdom": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/html-to-vdom/-/html-to-vdom-0.7.0.tgz", - "integrity": "sha512-k+d2qNkbx0JO00KezQsNcn6k2I/xSBP4yXYFLvXbcasTTDh+RDLUJS3puxqyNnpdyXWRHFGoKU7cRmby8/APcQ==", - "license": "ISC", - "dependencies": { - "ent": "^2.0.0", - "htmlparser2": "^3.8.2" - } - }, - "node_modules/htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "license": "MIT", - "dependencies": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" + "he": "bin/he" } }, "node_modules/http-cache-semantics": { @@ -2737,43 +2701,20 @@ "node": ">=8" } }, - "node_modules/is-in-ssh": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", - "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", - "license": "MIT", + "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": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, + "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": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/is-promise": { @@ -2781,45 +2722,17 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, + "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2840,23 +2753,10 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jpeg-exif": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", - "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, "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==", - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2967,45 +2867,34 @@ "json-buffer": "3.0.1" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", + "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": { - "immediate": "~3.0.5" - } - }, - "node_modules/linebreak": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", - "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", - "license": "MIT", - "dependencies": { - "base64-js": "0.0.8", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/linebreak/node_modules/base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", - "license": "MIT", + "p-locate": "^5.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" + "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", @@ -3142,11 +3031,48 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT" + "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", @@ -3309,58 +3235,32 @@ "node": ">=8" } }, - "node_modules/pac-proxy-agent": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", - "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", - "license": "MIT", + "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": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 14" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", + "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": { - "agent-base": "^7.1.2", - "debug": "4" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" + "node": ">=10" }, - "engines": { - "node": ">= 14" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json-from-dist": { @@ -3417,6 +3317,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", @@ -3470,40 +3378,7 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/png-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", - "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" - }, - "node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/progress": { "version": "2.0.3", @@ -3669,6 +3544,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", @@ -3705,11 +3588,22 @@ "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==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3901,6 +3795,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", @@ -4172,6 +4074,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", @@ -4183,46 +4096,20 @@ "node": ">= 8.0" } }, - "node_modules/tar-fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", - "license": "MIT", + "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": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" + "has-flag": "^4.0.0" }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "license": "MIT" - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -4466,6 +4353,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", @@ -4584,110 +4476,10 @@ } } }, - "node_modules/wsl-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.0.tgz", - "integrity": "sha512-3sFIGLiaDP7rTO4xh3g+b3AzhYDIUGGywE/WsmqzJWDxus5aJXVnPTNC/6L+r2WzrwXqVOdD262OaO+cEyPMSQ==", - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0", - "powershell-utils": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/x-is-array": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz", - "integrity": "sha512-goHPif61oNrr0jJgsXRfc8oqtYzvfiMJpTqwE7Z4y9uH+T3UozkGqQ4d2nX9mB9khvA8U2o/UbPOFjgC7hLWIA==" - }, - "node_modules/x-is-string": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha512-GojqklwG8gpzOVEVki5KudKNoq7MbbjYZCbyWzEz7tyPA7eleiE0+ePwOWQQRb5fm86rD3S8Tc0tSFf3AOv50w==" - }, - "node_modules/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", - "license": "MIT" - }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "license": "MIT", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - }, - "node_modules/xmlbuilder2": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.1.2.tgz", - "integrity": "sha512-PI710tmtVlQ5VmwzbRTuhmVhKnj9pM8Si+iOZCV2g2SNo3gCrpzR2Ka9wNzZtqfD+mnP+xkrqoNy0sjKZqP4Dg==", - "license": "MIT", - "dependencies": { - "@oozcitak/dom": "1.15.5", - "@oozcitak/infra": "1.0.5", - "@oozcitak/util": "8.3.3" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/xmlbuilder2/node_modules/@oozcitak/dom": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.5.tgz", - "integrity": "sha512-L6v3Mwb0TaYBYgeYlIeBaHnc+2ZEaDSbFiRm5KmqZQSoBlbPlf+l6aIH/sD5GUf2MYwULw00LT7+dOnEuAEC0A==", - "license": "MIT", - "dependencies": { - "@oozcitak/infra": "1.0.5", - "@oozcitak/url": "1.0.0", - "@oozcitak/util": "8.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/xmlbuilder2/node_modules/@oozcitak/dom/node_modules/@oozcitak/util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz", - "integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw==", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/xmlbuilder2/node_modules/@oozcitak/util": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.3.tgz", - "integrity": "sha512-Ufpab7G5PfnEhQyy5kDg9C8ltWJjsVT1P/IYqacjstaqydG4Q21HAT2HUZQYBrC/a1ZLKCz87pfydlDvv8y97w==", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", "engines": { "node": ">=10" } @@ -4696,7 +4488,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -4714,11 +4505,24 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", "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", @@ -4738,13 +4542,15 @@ "node": ">=6" } }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", + "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/colinhacks" + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index 5b59da6..bdb3fe0 100644 --- a/package.json +++ b/package.json @@ -3,18 +3,12 @@ "@google/genai": "^1.30.0", "@types/axios": "^0.9.36", "axios": "^1.13.2", - "cli-progress": "^3.12.0", - "docx": "^9.5.1", "dotenv": "^17.2.3", "electron": "^39.1.1", "express": "^5.1.0", "ffmpeg-static": "^5.2.0", "fluent-ffmpeg": "^2.1.3", - "html-to-docx": "^1.8.0", - "marked": "^17.0.1", - "open": "^11.0.0", - "pdfkit": "^0.17.2", - "puppeteer": "^24.33.0" + "mocha": "^11.7.5" }, "devDependencies": { "@types/cli-progress": "^3.11.6", @@ -33,7 +27,7 @@ }, "scripts": { "start": "electron main.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha ./test/unit/test.js" }, "repository": { "type": "git", diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 36a15fc..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -fastapi -uvicorn -pytest diff --git a/requires.js b/requires.js index 6036867..da3b9aa 100644 --- a/requires.js +++ b/requires.js @@ -11,12 +11,11 @@ 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'); electron = require('electron'); -genai = require("@google/genai"); axios = require("axios") diff --git a/scripts/show-models.js b/scripts/show-models.js new file mode 100644 index 0000000..9aae541 --- /dev/null +++ b/scripts/show-models.js @@ -0,0 +1,47 @@ +const fs = require('fs'); +const path = require('path'); + +//node show-models.js, remember to set SAIA_API_KEY in your environment before running the script + +const SAIA_API_KEY = process.env.SAIA_API_KEY; +const SAIA_MODELS_URL = "https://chat-ai.academiccloud.de/v1/models"; + +// Script to list available models +(async () => { + if (!SAIA_API_KEY) { + console.error("ERROR: SAIA_API_KEY environment variable is not set!"); + process.exit(1); + } + + console.log("Fetching available models from SAIA...\n"); + + try { + const response = await fetch(SAIA_MODELS_URL, { + method: "GET", + headers: { + "Authorization": `Bearer ${SAIA_API_KEY}`, + "Accept": "application/json" + } + }); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`SAIA API error (${response.status}): ${text}`); + } + + const data = await response.json(); + + console.log("Available models:"); + console.log(JSON.stringify(data, null, 2)); + + if (data.data && Array.isArray(data.data)) { + console.log("\n\nModel IDs:"); + data.data.forEach(model => { + console.log(`- ${model.id}`); + }); + } + + } catch (error) { + console.error("Error fetching models:", error); + } +})(); \ No newline at end of file diff --git a/services/modules/extraction/ffmpegExtractor.js b/services/modules/extraction/ffmpegExtractor.js index 2f00b15..c91eacf 100644 --- a/services/modules/extraction/ffmpegExtractor.js +++ b/services/modules/extraction/ffmpegExtractor.js @@ -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); } }); } diff --git a/services/modules/jsonTools/transcriptionSummarizer.js b/services/modules/jsonTools/transcriptionSummarizer.js index 745c5b7..1be34a3 100644 --- a/services/modules/jsonTools/transcriptionSummarizer.js +++ b/services/modules/jsonTools/transcriptionSummarizer.js @@ -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); } }) diff --git a/services/modules/jsonTools/transcriptionSummarizer2.js b/services/modules/jsonTools/transcriptionSummarizer2.js index 60d0bb8..aefe70c 100644 --- a/services/modules/jsonTools/transcriptionSummarizer2.js +++ b/services/modules/jsonTools/transcriptionSummarizer2.js @@ -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); } }) diff --git a/services/modules/llm-chat_gpt/chatgpt.js b/services/modules/llm-chat_gpt/chatgpt.js index 8446af5..76fa3a3 100644 --- a/services/modules/llm-chat_gpt/chatgpt.js +++ b/services/modules/llm-chat_gpt/chatgpt.js @@ -1,8 +1,131 @@ -module.exports = { - name:"chatgpt", // Unique name for our function that will later be used to get the function from the map via "mapFunctions.get("example").function()" - type:"llm", // value used to differentiate each module to order them in the UI - displayname:"ChatGPT", // The displayname used within the UI - async function(parameter){ - // TODO add code to actually send the transcript to ChatGPT and get a response back +const fs = require('fs'); +const path = require('path'); + +const outputDir = path.join(__dirname, "../../../storage/documents"); // path for output directory + +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); // Create output directory if it doesn't exist +} + +// Ensure SAIA API key is set in environment variables: export SAIA_API_KEY="your_api_key_here" +const SAIA_API_KEY = process.env.SAIA_API_KEY; // Ensure SAIA API key is set in environment variables + +const SAIA_URL = "https://chat-ai.academiccloud.de/v1/chat/completions"; //URL for the REST call, used model and action + +const module_exports = { + name: "llm-saia_openai_gpt", + type: "llm", + displayname: "GPT 120B", + description: "Generates documents using OpenAI GPT OSS 120B via SAIA platform", + + async function(parameter) { + try { + console.log("SAIA OpenAI GPT 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 + ); + + } catch (error) { + console.error("Error in SAIA OpenAI GPT 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 + + // --- REST CALL --- + const response = await fetch(SAIA_URL, { + method: "POST", + headers: { + "Authorization": `Bearer ${SAIA_API_KEY}`, + "Accept": "application/json", + "Content-Type": "application/json" + }, + body: JSON.stringify({ + model: "openai-gpt-oss-120b", + messages: [ + { role: "system", content: "You are a helpful assistant that generates documents from transcripts." }, + { role: "user", content: promptText } + ], + temperature: 0 + }) + }); + + if (!response.ok) { //ok is true when a response was successful + const text = await response.text(); + throw new Error(`SAIA API error (${response.status}): ${text}`); + } + + const data = await response.json(); + + // Get generated text from response or default to empty string (if null) + // SAIA uses OpenAI-compatible structure: data.choices[x].message.content + const output = data.choices?.[0]?.message?.content || ""; + + 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 SAIA content:", error); + } } +}; + +module.exports = module_exports; + +// CLI Mode: Allow direct execution +if (require.main === module) { + (async () => { + const args = process.argv.slice(2); + + if (args.length < 2) { + console.error("Usage: node llm-openai-gpt.js [language]"); + console.error("Example: node llm-openai-gpt.js ./transcript.json ./docType.json de"); + process.exit(1); + } + + const [transcriptPath, documentTypePath, language] = args; + + // Check if API key is set + if (!SAIA_API_KEY) { + console.error("ERROR: SAIA_API_KEY environment variable is not set!"); + console.error("Please set it with: export SAIA_API_KEY='your_api_key_here'"); + process.exit(1); + } + + // Check if files exist + if (!fs.existsSync(transcriptPath)) { + console.error(`ERROR: Transcript file not found: ${transcriptPath}`); + process.exit(1); + } + + if (!fs.existsSync(documentTypePath)) { + console.error(`ERROR: Document type file not found: ${documentTypePath}`); + process.exit(1); + } + + console.log("Starting document generation..."); + console.log(`Transcript: ${transcriptPath}`); + console.log(`Document Type: ${documentTypePath}`); + console.log(`Language: ${language || 'en (default)'}`); + + await module_exports.createDocumentFromTranscript( + transcriptPath, + documentTypePath, + language || 'en' + ); + + console.log("Done!"); + })(); } \ No newline at end of file diff --git a/services/modules/llm-gemini/gemini.js b/services/modules/llm-gemini/gemini.js index 6bd88a6..214c81c 100644 --- a/services/modules/llm-gemini/gemini.js +++ b/services/modules/llm-gemini/gemini.js @@ -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); - } + }) } }; \ No newline at end of file diff --git a/services/modules/llm-llama/llm-llama.js b/services/modules/llm-llama/llm-llama.js new file mode 100644 index 0000000..4e6d920 --- /dev/null +++ b/services/modules/llm-llama/llm-llama.js @@ -0,0 +1,123 @@ +const fs = require('fs'); +const path = require('path'); + +const outputDir = path.join(__dirname, "../../../storage/documents"); + +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); +} + +const SAIA_API_KEY = process.env.SAIA_API_KEY; +const SAIA_URL = "https://chat-ai.academiccloud.de/v1/chat/completions"; + +const module_exports = { + name: "llm-saia_llama_3.3", + type: "llm", + displayname: "LLAMA", + description: "Generates documents using Llama 3.3 70B Instruct via SAIA platform", + + async function(parameter) { + try { + console.log("SAIA Llama 3.3 70B module invoked with parameters:", parameter); + + await this.createDocumentFromTranscript( + parameter.inputTranscriptPath, + parameter.documentTypePath, + parameter.language + ); + + } catch (error) { + console.error("Error in SAIA Llama 3.3 70B module:", error); + } + }, + + createDocumentFromTranscript: async function(transcriptPath, documentTypePath, language = "en") { + try { + const transcript = await fs.promises.readFile(transcriptPath, "utf-8"); + const documentType = await fs.promises.readFile(documentTypePath, "utf-8"); + const promptText = `${documentType}, in language ${language}, transcript:\n\n${transcript}`; + + // --- REST CALL --- + const response = await fetch(SAIA_URL, { + method: "POST", + headers: { + "Authorization": `Bearer ${SAIA_API_KEY}`, + "Accept": "application/json", + "Content-Type": "application/json" + }, + body: JSON.stringify({ + model: "llama-3.3-70b-instruct", // Korrekter Modellname! + messages: [ + { role: "system", content: "You are a helpful assistant that generates documents from transcripts." }, + { role: "user", content: promptText } + ], + temperature: 0 + }) + }); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`SAIA API error (${response.status}): ${text}`); + } + + const data = await response.json(); + const output = data.choices?.[0]?.message?.content || ""; + + let inputTranscriptName = path.basename(transcriptPath, path.extname(transcriptPath)); + console.log(inputTranscriptName); + + const outPath = path.join(outputDir, `${inputTranscriptName}.md`); + fs.writeFileSync(outPath, output, "utf8"); + + console.log("Generated document written to:", outPath); + + } catch (error) { + console.error("Error generating SAIA content:", error); + } + } +}; + +module.exports = module_exports; + +if (require.main === module) { + (async () => { + const args = process.argv.slice(2); + + if (args.length < 2) { + console.error("Usage: node llm-llama-3.3.js [language]"); + console.error("Example: node llm-llama-3.3.js ./transcript.json ./docType.json de"); + process.exit(1); + } + + const [transcriptPath, documentTypePath, language] = args; + + if (!SAIA_API_KEY) { + console.error("ERROR: SAIA_API_KEY environment variable is not set!"); + console.error("Please set it with: export SAIA_API_KEY='your_api_key_here'"); + process.exit(1); + } + + if (!fs.existsSync(transcriptPath)) { + console.error(`ERROR: Transcript file not found: ${transcriptPath}`); + process.exit(1); + } + + if (!fs.existsSync(documentTypePath)) { + console.error(`ERROR: Document type file not found: ${documentTypePath}`); + process.exit(1); + } + + console.log("Starting document generation..."); + console.log(`Transcript: ${transcriptPath}`); + console.log(`Document Type: ${documentTypePath}`); + console.log(`Language: ${language || 'en (default)'}`); + + await module_exports.createDocumentFromTranscript( + transcriptPath, + documentTypePath, + language || 'en' + ); + + console.log("Done!"); + })(); +} \ No newline at end of file diff --git a/services/modules/transcription-local/whisper.cpp b/services/modules/transcription-local/whisper.cpp new file mode 160000 index 0000000..999a7e0 --- /dev/null +++ b/services/modules/transcription-local/whisper.cpp @@ -0,0 +1 @@ +Subproject commit 999a7e0cbf8484dc2cea1e9f855d6b39f34f7ae9 diff --git a/services/modules/transcription-remote/assembly.js b/services/modules/transcription-remote/assembly.js index 5819a3c..442d290 100644 --- a/services/modules/transcription-remote/assembly.js +++ b/services/modules/transcription-remote/assembly.js @@ -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 } }) } diff --git a/services/modules/utility/@startup.js b/services/modules/utility/@startup.js index cf6eaf8..64f0b20 100644 --- a/services/modules/utility/@startup.js +++ b/services/modules/utility/@startup.js @@ -1,3 +1,4 @@ + module.exports = { name:"Startup_function", async function(){ diff --git a/test/.gitkeep b/storage/documentType/.gitkeep similarity index 100% rename from test/.gitkeep rename to storage/documentType/.gitkeep diff --git a/storage/documentType/meetingReport.json b/storage/documentType/meetingReport.json index 8d814f8..04626df 100644 --- a/storage/documentType/meetingReport.json +++ b/storage/documentType/meetingReport.json @@ -1,7 +1,6 @@ { - "SPEAKERS":"First Identify each speaker in the transcript and give the first time snippet where they speak for the first time. Use labels like Speaker 1, Speaker 2, etc. If no speakers are identified, use 'Speaker X'.", - "FORMAT": "HTML", - "GOAL":"Generate a structured meeting report (HTML). **Output ONLY:** final .html. No meta.", + "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", @@ -16,21 +15,19 @@ "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": "UNKNOWN:" + "unclear": "UNKLAR:" }, - + "JSON_OUTPUT_OPTIONAL": true, - "PROMPT_SNIPPET": "Generate meeting report in HTML using STRUCTURE and STYLE. Output only the report." + "PROMPT_SNIPPET": "Generate meeting report in markdown using STRUCTURE and STYLE. Output only the report." } \ No newline at end of file diff --git a/test/unit/.gitkeep b/storage/documents/.gitkeep similarity index 100% rename from test/unit/.gitkeep rename to storage/documents/.gitkeep diff --git a/storage/transcriptionSummaries/.gitkeep b/storage/transcriptionSummaries/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/test_health.py b/test/test_health.py deleted file mode 100644 index 7b088a7..0000000 --- a/test/test_health.py +++ /dev/null @@ -1,8 +0,0 @@ -from fastapi.testclient import TestClient -from app.main import app - -client = TestClient(app) - -def test_health(): - response = client.get("/health") - assert response.status_code == 200 diff --git a/test/unit/test.js b/test/unit/test.js new file mode 100644 index 0000000..3560969 --- /dev/null +++ b/test/unit/test.js @@ -0,0 +1,170 @@ +// 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(120000) + + 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(120000) + + // 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}`); + }) +}) + + diff --git a/test/unit/testvideo.mp4 b/test/unit/testvideo.mp4 new file mode 100644 index 0000000..625a31f Binary files /dev/null and b/test/unit/testvideo.mp4 differ