From dc4e57db2cdadeb89f19596064a12142f72d1268 Mon Sep 17 00:00:00 2001 From: Ken Yasue Date: Sun, 17 Aug 2025 17:47:54 +0200 Subject: [PATCH 01/15] save current changes --- package-lock.json | 279 +++++++++++++++++++++++++++++++++++++ package.json | 6 +- src/generateImage.ts | 81 +++++++++++ src/generatePrompt.ts | 116 +++++++++++++++ src/index_prompt.ts | 20 +++ src/lib/db/schema.ts | 53 +++++++ src/lib/db/tag.ts | 58 ++++++++ src/lib/db/tag_video.ts | 46 ++++++ src/lib/db/video.ts | 59 ++++++++ src/lib/image-describer.ts | 63 +-------- src/lib/image-generator.ts | 7 +- src/lib/lmstudio.ts | 115 +++++++++++++++ src/lib/mysql.ts | 33 +++++ src/lib/video-generator.ts | 7 +- src/testmysql.ts | 69 +++++++++ 15 files changed, 944 insertions(+), 68 deletions(-) create mode 100644 src/generateImage.ts create mode 100644 src/generatePrompt.ts create mode 100644 src/lib/db/schema.ts create mode 100644 src/lib/db/tag.ts create mode 100644 src/lib/db/tag_video.ts create mode 100644 src/lib/db/video.ts create mode 100644 src/lib/lmstudio.ts create mode 100644 src/lib/mysql.ts create mode 100644 src/testmysql.ts diff --git a/package-lock.json b/package-lock.json index 3b15d4b..d83113d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,13 @@ "@types/axios": "^0.14.4", "axios": "^1.11.0", "dotenv": "^17.2.1", + "mysql2": "^3.14.3", "open": "^10.2.0", "puppeteer": "^24.16.2" }, "devDependencies": { "@types/node": "^20.0.0", + "ts-node": "^10.9.2", "typescript": "^5.0.0" } }, @@ -41,6 +43,43 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@puppeteer/browsers": { "version": "2.10.6", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.6.tgz", @@ -66,6 +105,30 @@ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@types/axios": { "version": "0.14.4", "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.4.tgz", @@ -93,6 +156,30 @@ "@types/node": "*" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -123,6 +210,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -144,6 +237,14 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/axios": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", @@ -353,6 +454,12 @@ } } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -435,11 +542,28 @@ "node": ">=0.4.0" } }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/devtools-protocol": { "version": "0.0.1475386", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1475386.tgz", "integrity": "sha512-RQ809ykTfJ+dgj9bftdeL2vRVxASAuGU+I9LEx9Ij5TXU5HrgAQVmzi72VA+mkzscE12uzlRv5/tWWv9R9J1SA==" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dotenv": { "version": "17.2.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", @@ -664,6 +788,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -805,6 +937,17 @@ "node": ">= 14" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -872,6 +1015,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, "node_modules/is-wsl": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", @@ -912,6 +1060,11 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -920,6 +1073,26 @@ "node": ">=12" } }, + "node_modules/lru.min": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz", + "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -957,6 +1130,36 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/mysql2": { + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.3.tgz", + "integrity": "sha512-fD6MLV8XJ1KiNFIF0bS7Msl8eZyhlTDCDl75ajU5SJtpdx9ZPEACulJcqJWr1Y8OYyxsFc4j3+nflpmhxCU5aQ==", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -1161,6 +1364,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -1172,6 +1380,11 @@ "node": ">=10" } }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -1216,6 +1429,14 @@ "node": ">=0.10.0" } }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/streamx": { "version": "2.22.1", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", @@ -1283,6 +1504,49 @@ "b4a": "^1.6.4" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1312,6 +1576,12 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "devOptional": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1409,6 +1679,15 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/package.json b/package.json index e9924de..d75f5ee 100644 --- a/package.json +++ b/package.json @@ -6,19 +6,23 @@ "scripts": { "start": "tsc && node dist/index.js", "build": "tsc", - "test": "echo \"Error: no test specified\" && exit 1" +"test": "echo \"Error: no test specified\" && exit 1", +"db:schema": "ts-node src/schema.ts", +"db:test": "ts-node src/testmysql.ts" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@types/node": "^20.0.0", + "ts-node": "^10.9.2", "typescript": "^5.0.0" }, "dependencies": { "@types/axios": "^0.14.4", "axios": "^1.11.0", "dotenv": "^17.2.1", + "mysql2": "^3.14.3", "open": "^10.2.0", "puppeteer": "^24.16.2" } diff --git a/src/generateImage.ts b/src/generateImage.ts new file mode 100644 index 0000000..6c7aa4b --- /dev/null +++ b/src/generateImage.ts @@ -0,0 +1,81 @@ +import { query } from './lib/mysql'; +import { generateImage } from './lib/image-generator'; +import { logger } from './lib/logger'; +import dotenv from 'dotenv'; + +dotenv.config(); + +interface VideoRecord { + id: number; + genre: string; + sub_genre: string; + image_prompt: string; + // Add other fields if necessary +} + +const servers = [ + { + baseUrl: process.env.SERVER1_COMFY_BASE_URL, + outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR, + }, + { + baseUrl: process.env.SERVER2_COMFY_BASE_URL, + outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR, + }, +]; + +async function processServerQueue(server: any, videos: any[]) { + for (const video of videos) { + try { + const fileName = `${video.id}_${video.genre}_${video.sub_genre}.png`.replace(/\s/g, '_'); + const imagePath = await generateImage( + video.image_prompt, + fileName, + server.baseUrl, + server.outputDir, + 'flux', + { width: 720, height: 1280 } + ); + + await query('UPDATE video SET image_path = ? WHERE id = ?', [imagePath, video.id]); + logger.info(`Generated and saved image for video ${video.id} at ${imagePath}`); + } catch (error) { + logger.error(`Failed to generate image for video ${video.id}:`, error); + } + } +} + +async function main() { + try { + const videosToProcess = await query( + "SELECT * FROM video WHERE image_prompt IS NOT NULL AND (image_path IS NULL OR image_path = '')" + ) as any[]; + + if (videosToProcess.length === 0) { + logger.info('No images to generate.'); + return; + } + + const queues: VideoRecord[][] = servers.map(() => []); + videosToProcess.forEach((video, index) => { + queues[index % servers.length].push(video); + }); + + const promises = servers.map((server, index) => { + if (!server.baseUrl || !server.outputDir) { + logger.warn(`Server ${index + 1} is not configured. Skipping.`); + return Promise.resolve(); + } + return processServerQueue(server, queues[index]); + }); + + await Promise.all(promises); + logger.info('Finished generating all images.'); + } catch (error) { + logger.error('An error occurred during image generation:', error); + } finally { + process.exit(); + } +} + +main(); diff --git a/src/generatePrompt.ts b/src/generatePrompt.ts new file mode 100644 index 0000000..68e7c65 --- /dev/null +++ b/src/generatePrompt.ts @@ -0,0 +1,116 @@ +import fs from 'fs'; +import path from 'path'; +import { query } from './lib/mysql'; +import { logger } from './lib/logger'; +import { callLMStudio } from './lib/lmstudio'; + +async function main() { + //await insertGenres(); + await generatePrompts(); + process.exit(); +} + +async function insertGenres() { + logger.info('Starting genre insertion...'); + try { + const genresPath = path.join(__dirname, 'data', 'genres.json'); + const genresData = JSON.parse(fs.readFileSync(genresPath, 'utf-8')); + + for (const genre in genresData) { + if (genresData.hasOwnProperty(genre)) { + const items = genresData[genre]; + for (let item of items) { + if (Array.isArray(item)) { + for (const subItem of item) { + await processItem(genre, subItem); + } + } else { + await processItem(genre, item); + } + } + } + } + logger.info('Finished processing genres.'); + } catch (error) { + logger.error('Error processing genres:', error); + } +} + +async function generatePrompts() { + logger.info('Starting prompt generation...'); + try { + const videosToUpdate = await query( + 'SELECT * FROM video WHERE image_prompt IS NULL OR video_prompt IS NULL' + ) as any[]; + + for (const video of videosToUpdate) { + const prompt = ` + Based on the following video details, generate an image prompt and a video prompt. + Each prompt should be around 100 words. + The output should be a JSON object in the format: { "imagePrompt": "...", "videoPrompt": "..." } + For video prompt, it takes 8 seconds. So start with current scene, describe action and camera work. + Please include lighting details too. + + Details: + - Genre: ${video.genre} + - Sub-Genre: ${video.sub_genre} + - Scene: ${video.scene} + - Action: ${video.action} + - Camera: ${video.camera} + `; + + logger.info(`Generating prompt for video ID: ${video.id}`); + logger.debug(prompt); + + let success = false; + for (let i = 0; i < 10; i++) { + try { + const response = await callLMStudio(prompt); + if (response && response.imagePrompt && response.videoPrompt) { + await query( + 'UPDATE video SET image_prompt = ?, video_prompt = ? WHERE id = ?', + [response.imagePrompt, response.videoPrompt, video.id] + ); + logger.info(`Successfully updated prompts for video ID: ${video.id}`); + success = true; + break; + } + } catch (error) { + logger.warn(`Attempt ${i + 1} failed for video ID ${video.id}:`, error); + } + } + + if (!success) { + logger.error(`Failed to generate and parse prompts for video ID: ${video.id} after 10 attempts.`); + } + } + logger.info('Finished generating prompts.'); + } catch (error) { + logger.error('Error generating prompts:', error); + } +} + +async function processItem(genre: string, item: any) { + if (item && typeof item === 'object' && !Array.isArray(item)) { + const { subGenre, scene, action, camera } = item; + + // Check if the item already exists + const existing = await query( + 'SELECT id FROM video WHERE genre = ? AND sub_genre = ? AND scene = ? AND action = ? AND camera = ?', + [genre, subGenre, scene, action, camera] + ) as any[]; + + if (existing.length === 0) { + // Insert the new item + await query( + 'INSERT INTO video (genre, sub_genre, scene, action, camera) VALUES (?, ?, ?, ?, ?)', + [genre, subGenre, scene, action, camera] + ); + logger.info(`Inserted: ${genre} - ${subGenre} - ${scene}`); + } else { + logger.info(`Skipped (exists): ${genre} - ${subGenre} - ${scene}`); + } + } +} + +main(); diff --git a/src/index_prompt.ts b/src/index_prompt.ts index c6ade89..f897eb1 100644 --- a/src/index_prompt.ts +++ b/src/index_prompt.ts @@ -3,6 +3,12 @@ import { generateVideo } from './lib/video-generator'; import { logger } from './lib/logger'; import { Scene } from './types'; import scenes from './scenes/space.json'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const COMFY_BASE_URL = process.env.COMFY_BASE_URL; +const COMFY_OUTPUT_DIR = process.env.COMFY_OUTPUT_DIR; interface ProcessedScene { scene: Scene; @@ -10,6 +16,11 @@ interface ProcessedScene { } async function prepareImageForScene(scene: Scene): Promise { + if (!COMFY_BASE_URL || !COMFY_OUTPUT_DIR) { + logger.error('COMFY_BASE_URL and COMFY_OUTPUT_DIR must be set in the environment variables.'); + return null; + } + try { const startTime = Date.now(); logger.info(`--- Preparing image for scene: ${scene.idea} ---`); @@ -19,6 +30,8 @@ async function prepareImageForScene(scene: Scene): Promise): Promise { + const sql = 'INSERT INTO tag (tag) VALUES (?)'; + const params = [tag.tag]; + const result: any = await query(sql, params); + return result.insertId; + } + + static async getById(id: number): Promise { + const sql = 'SELECT * FROM tag WHERE id = ?'; + const params = [id]; + const rows: any = await query(sql, params); + return rows.length > 0 ? rows[0] as Tag : null; + } + + static async getByTag(tag: string): Promise { + const sql = 'SELECT * FROM tag WHERE tag = ?'; + const params = [tag]; + const rows: any = await query(sql, params); + return rows.length > 0 ? rows[0] as Tag : null; + } + + static async getAll(): Promise { + const sql = 'SELECT * FROM tag'; + const rows: any = await query(sql); + return rows as Tag[]; + } + + static async update(id: number, tag: Partial>): Promise { + const fields = Object.keys(tag); + const values = Object.values(tag); + + if (fields.length === 0) { + return false; + } + + const sql = `UPDATE tag SET ${fields.map(field => `${field} = ?`).join(', ')} WHERE id = ?`; + const params = [...values, id]; + const result: any = await query(sql, params); + return result.affectedRows > 0; + } + + static async delete(id: number): Promise { + const sql = 'DELETE FROM tag WHERE id = ?'; + const params = [id]; + const result: any = await query(sql, params); + return result.affectedRows > 0; + } +} diff --git a/src/lib/db/tag_video.ts b/src/lib/db/tag_video.ts new file mode 100644 index 0000000..c0f2b2b --- /dev/null +++ b/src/lib/db/tag_video.ts @@ -0,0 +1,46 @@ +import { query } from '../mysql'; + +export interface TagVideo { + id: number; + created_at: Date; + modified_at: Date; + tag_id: number; + video_id: number; +} + +export class TagVideoModel { + static async create(tagVideo: Omit): Promise { + const sql = 'INSERT INTO tag_video (tag_id, video_id) VALUES (?, ?)'; + const params = [tagVideo.tag_id, tagVideo.video_id]; + const result: any = await query(sql, params); + return result.insertId; + } + + static async getByVideoId(videoId: number): Promise { + const sql = 'SELECT * FROM tag_video WHERE video_id = ?'; + const params = [videoId]; + const rows: any = await query(sql, params); + return rows as TagVideo[]; + } + + static async getByTagId(tagId: number): Promise { + const sql = 'SELECT * FROM tag_video WHERE tag_id = ?'; + const params = [tagId]; + const rows: any = await query(sql, params); + return rows as TagVideo[]; + } + + static async delete(id: number): Promise { + const sql = 'DELETE FROM tag_video WHERE id = ?'; + const params = [id]; + const result: any = await query(sql, params); + return result.affectedRows > 0; + } + + static async deleteByTagAndVideo(tagId: number, videoId: number): Promise { + const sql = 'DELETE FROM tag_video WHERE tag_id = ? AND video_id = ?'; + const params = [tagId, videoId]; + const result: any = await query(sql, params); + return result.affectedRows > 0; + } +} diff --git a/src/lib/db/video.ts b/src/lib/db/video.ts new file mode 100644 index 0000000..091d06a --- /dev/null +++ b/src/lib/db/video.ts @@ -0,0 +1,59 @@ +import { query } from '../mysql'; + +export interface Video { + id: number; + created_at: Date; + modified_at: Date; + genre: string; + sub_genre: string; + scene: string; + action: string; + camera: string; + image_prompt: string; + video_prompt: string; + image_path: string; + video_path: string; +} + +export class VideoModel { + static async create(video: Omit): Promise { + const sql = 'INSERT INTO video (genre, sub_genre, scene, action, camera, image_prompt, video_prompt, image_path, video_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'; + const params = [video.genre, video.sub_genre, video.scene, video.action, video.camera, video.image_prompt, video.video_prompt, video.image_path, video.video_path]; + const result: any = await query(sql, params); + return result.insertId; + } + + static async getById(id: number): Promise