diff --git a/devbox.d/caddy/Caddyfile b/devbox.d/caddy/Caddyfile deleted file mode 100644 index 8d06494..0000000 --- a/devbox.d/caddy/Caddyfile +++ /dev/null @@ -1,15 +0,0 @@ -# See https://caddyserver.com/docs/caddyfile for more details -{ - admin 0.0.0.0:2020 - auto_https disable_certs - http_port 8800 - https_port 4443 -} - -:8082 { - root * {$CADDY_ROOT_DIR} - log { - output file {$CADDY_LOG_DIR}/caddy.log - } - file_server -} diff --git a/devbox.d/web/index.html b/devbox.d/web/index.html deleted file mode 100644 index 21250f0..0000000 --- a/devbox.d/web/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Hello World! - - - Hello World! - - diff --git a/devbox.json b/devbox.json deleted file mode 100644 index 10813f3..0000000 --- a/devbox.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.12.0/.schema/devbox.schema.json", - "packages": [ - "nodejs@20", - "ffmpeg@latest", - "yt-dlp@latest", - "lazydocker@latest", - "chisel@latest", - "entr@latest", - "act@latest", - "git-subrepo@latest", - "opentofu@latest", - "ggshield@latest", - "python310@latest", - "python310Packages.pip@latest", - "caddy@latest" - ], - "env": { - "DEVBOX_COREPACK_ENABLED": "true", - "ENV": "development", - "KUBECONFIG": "$HOME/.kube/futureporn.yaml", - "VENV_DIR": ".venv" - }, - "shell": { - "init_hook": [ - "echo Welcome to Futureporn devbox", - ". $VENV_DIR/bin/activate", - "pip install -r requirements.txt" - ], - "scripts": { - "tunnel": "dotenvx run -f ./.env.development -- chisel client bright.fp.sbtp.xyz:9090 R:4000", - "backup": "docker exec -t postgres_db pg_dumpall -c -U postgres > ./backups/dev_`date +%Y-%m-%d_%H_%M_%S`.sql", - "act": "dotenvx run -f ./.env.testing -- act -W ./.gitea/workflows --secret-file .env.development", - "act:builder": "dotenvx run -f ./.env.testing -- act --env-file .env.testing -W ./.gitea/workflows/builder.yaml --secret-file .env.testing --var-file .env.testing --insecure-secrets", - "act:tests": "dotenvx run -f ./.env.testing -- act --env-file .env.testing -W ./.gitea/workflows/tests.yaml --secret-file .env.testing --var-file .env.testing --insecure-secrets", - "bright:compile:watch": "cd ./apps/bright && find . -type f -name \"*.ex\" -o -name \"*.exs\" | entr -r mix compile --warnings-as-errors", - "bright:compile:watch2": "cd ./apps/bright && pnpx chokidar-cli \"**/*\" -i \"deps/**\" -i \"_build/**\" -c \"mix compile --warnings-as-errors\"", - "bright:dev": "cd ./apps/bright && dotenvx run -f ../../.env.development -e MIX_ENV=dev -- mix phx.server", - "bright:test:unit:watch": "cd ./apps/bright && pnpx chokidar-cli '**/*' -i \"deps/**\" -i '_build/**' -c 'mix test --only=unit'", - "bright:act": "cd ./apps/bright && act --env MIX_ENV=test -W ./.gitea/workflows/tests.yaml --secret-file .env.development", - "test": "act -W ./.gitea/workflows/tests.yaml --secret-file .env.testing --var-file .env.testing && devbox run beep || devbox run boop", - "beep": "ffplay -nodisp -loglevel quiet -autoexit ./apps/beep/beep2.wav", - "boop": "ffplay -nodisp -loglevel quiet -autoexit ./apps/beep/beep1.wav" - } - } -} \ No newline at end of file diff --git a/devbox.lock b/devbox.lock deleted file mode 100644 index d11aeb8..0000000 --- a/devbox.lock +++ /dev/null @@ -1,827 +0,0 @@ -{ - "lockfile_version": "1", - "packages": { - "act@latest": { - "last_modified": "2025-02-07T11:26:36Z", - "resolved": "github:NixOS/nixpkgs/d98abf5cf5914e5e4e9d57205e3af55ca90ffc1d#act", - "source": "devbox-search", - "version": "0.2.72", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/69mqjq6ysm38yppm5l0a68zaxfk3jsb5-act-0.2.72", - "default": true - } - ], - "store_path": "/nix/store/69mqjq6ysm38yppm5l0a68zaxfk3jsb5-act-0.2.72" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/di3cp7yr4dq07byl8hm8xwnas7hn8xcn-act-0.2.72", - "default": true - } - ], - "store_path": "/nix/store/di3cp7yr4dq07byl8hm8xwnas7hn8xcn-act-0.2.72" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yblc9543pbzncgy0q4bfdj8h7nrs35am-act-0.2.72", - "default": true - } - ], - "store_path": "/nix/store/yblc9543pbzncgy0q4bfdj8h7nrs35am-act-0.2.72" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/k7nqxipi81pzfdbh2a19np9q84qmgj3w-act-0.2.72", - "default": true - } - ], - "store_path": "/nix/store/k7nqxipi81pzfdbh2a19np9q84qmgj3w-act-0.2.72" - } - } - }, - "caddy@latest": { - "last_modified": "2025-02-07T11:26:36Z", - "plugin_version": "0.0.3", - "resolved": "github:NixOS/nixpkgs/d98abf5cf5914e5e4e9d57205e3af55ca90ffc1d#caddy", - "source": "devbox-search", - "version": "2.9.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wsj8iixhs5iwjhfyy4l00va0dj301sjs-caddy-2.9.1", - "default": true - } - ], - "store_path": "/nix/store/wsj8iixhs5iwjhfyy4l00va0dj301sjs-caddy-2.9.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/w6cg28ws2404fglmhbzddqjjkniqfiam-caddy-2.9.1", - "default": true - } - ], - "store_path": "/nix/store/w6cg28ws2404fglmhbzddqjjkniqfiam-caddy-2.9.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8q0lw048apajs1rg6vpfbp2p1m37f25a-caddy-2.9.1", - "default": true - } - ], - "store_path": "/nix/store/8q0lw048apajs1rg6vpfbp2p1m37f25a-caddy-2.9.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ax0979vnibikl5cr180lmxvb80m2zq50-caddy-2.9.1", - "default": true - } - ], - "store_path": "/nix/store/ax0979vnibikl5cr180lmxvb80m2zq50-caddy-2.9.1" - } - } - }, - "chisel@latest": { - "last_modified": "2024-12-23T21:10:33Z", - "resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#chisel", - "source": "devbox-search", - "version": "1.10.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/2rls3b9lq2i3g53zpr09d6ph43mgfxwz-chisel-1.10.1", - "default": true - } - ], - "store_path": "/nix/store/2rls3b9lq2i3g53zpr09d6ph43mgfxwz-chisel-1.10.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7ff1z4mr0ia2ifdgggpqkbc2j795ccy4-chisel-1.10.1", - "default": true - } - ], - "store_path": "/nix/store/7ff1z4mr0ia2ifdgggpqkbc2j795ccy4-chisel-1.10.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/2cb5sa449vpah2g4q4prvqfz1dcf1rdw-chisel-1.10.1", - "default": true - } - ], - "store_path": "/nix/store/2cb5sa449vpah2g4q4prvqfz1dcf1rdw-chisel-1.10.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/pphc5mnhx6mb08ak6mb3rnh061427xbj-chisel-1.10.1", - "default": true - } - ], - "store_path": "/nix/store/pphc5mnhx6mb08ak6mb3rnh061427xbj-chisel-1.10.1" - } - } - }, - "entr@latest": { - "last_modified": "2025-01-19T08:16:51Z", - "resolved": "github:NixOS/nixpkgs/50165c4f7eb48ce82bd063e1fb8047a0f515f8ce#entr", - "source": "devbox-search", - "version": "5.6", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/2qbvxdg5asmjs0fjcf84mssrv5pw7apa-entr-5.6", - "default": true - } - ], - "store_path": "/nix/store/2qbvxdg5asmjs0fjcf84mssrv5pw7apa-entr-5.6" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xnhjmgv6svqp793vxhpfcvxig5yi9s60-entr-5.6", - "default": true - } - ], - "store_path": "/nix/store/xnhjmgv6svqp793vxhpfcvxig5yi9s60-entr-5.6" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/fknw34xxmp239x81r201drmlm3g9p1bb-entr-5.6", - "default": true - } - ], - "store_path": "/nix/store/fknw34xxmp239x81r201drmlm3g9p1bb-entr-5.6" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yy1d68xcy847axfmb5xws2271xkf61xk-entr-5.6", - "default": true - } - ], - "store_path": "/nix/store/yy1d68xcy847axfmb5xws2271xkf61xk-entr-5.6" - } - } - }, - "ffmpeg@latest": { - "last_modified": "2025-01-07T09:15:50Z", - "resolved": "github:NixOS/nixpkgs/8c9fd3e564728e90829ee7dbac6edc972971cd0f#ffmpeg", - "source": "devbox-search", - "version": "7.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "bin", - "path": "/nix/store/m48ypyjnl04mqigi6fbxa7k2c5bsvazz-ffmpeg-7.1-bin", - "default": true - }, - { - "name": "man", - "path": "/nix/store/10ncvfz8srnzckq16bn14wffcx8j04ki-ffmpeg-7.1-man", - "default": true - }, - { - "name": "data", - "path": "/nix/store/rqbsc9zyzi988hwcd423qdh1vh40zlzc-ffmpeg-7.1-data" - }, - { - "name": "dev", - "path": "/nix/store/6ml3pn92nbmnc40s5jfpr84y65ysizk3-ffmpeg-7.1-dev" - }, - { - "name": "doc", - "path": "/nix/store/ni6gri7m1pavfjxx0yfj1msvb0cfasgg-ffmpeg-7.1-doc" - }, - { - "name": "lib", - "path": "/nix/store/2v2rr9dmq4grzwmg4zcsxrmbdcshks7m-ffmpeg-7.1-lib" - }, - { - "name": "out", - "path": "/nix/store/nvccyp4dra8f92ywd00lk3ra121gj162-ffmpeg-7.1" - } - ], - "store_path": "/nix/store/m48ypyjnl04mqigi6fbxa7k2c5bsvazz-ffmpeg-7.1-bin" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "bin", - "path": "/nix/store/lj99z3ldzka2slgm94w2yl8cjkphn4m3-ffmpeg-7.1-bin", - "default": true - }, - { - "name": "man", - "path": "/nix/store/gisda8d2pifrrjw0yirrs0x2cyn6b96i-ffmpeg-7.1-man", - "default": true - }, - { - "name": "out", - "path": "/nix/store/pc332zx12j2fqf5m9mdhhs1rwksbk2fk-ffmpeg-7.1" - }, - { - "name": "data", - "path": "/nix/store/4yhsn6lrfn91dk1kq9wyyd71p4hcfans-ffmpeg-7.1-data" - }, - { - "name": "dev", - "path": "/nix/store/71103mmkxhzzmbj9mpzsrzbp988z3p98-ffmpeg-7.1-dev" - }, - { - "name": "doc", - "path": "/nix/store/k9cc4d60frcn27zapkzhag5h9r0ig5xa-ffmpeg-7.1-doc" - }, - { - "name": "lib", - "path": "/nix/store/dgcmpc8az51a4d2bxgrmfz8zlmvqxwa5-ffmpeg-7.1-lib" - } - ], - "store_path": "/nix/store/lj99z3ldzka2slgm94w2yl8cjkphn4m3-ffmpeg-7.1-bin" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "bin", - "path": "/nix/store/z44kr817zx99vi2cc204i06cnmz83f1n-ffmpeg-7.1-bin", - "default": true - }, - { - "name": "man", - "path": "/nix/store/slrha22nqrx2xw009hd37svv2nvpp26i-ffmpeg-7.1-man", - "default": true - }, - { - "name": "data", - "path": "/nix/store/n3xm2rr1k1ari7ysbp9jhg65pih28x6x-ffmpeg-7.1-data" - }, - { - "name": "dev", - "path": "/nix/store/59gcv4rfg38rqnazv1iq9jssjak2l3ih-ffmpeg-7.1-dev" - }, - { - "name": "doc", - "path": "/nix/store/2cqa3lc75ciqzgmxjm36fd733f3gjgil-ffmpeg-7.1-doc" - }, - { - "name": "lib", - "path": "/nix/store/ir47x8skj54wilcyz2x59am4y085lf6l-ffmpeg-7.1-lib" - }, - { - "name": "out", - "path": "/nix/store/gqw958wdgrbfsxczqf56vnq1iffg5qv1-ffmpeg-7.1" - } - ], - "store_path": "/nix/store/z44kr817zx99vi2cc204i06cnmz83f1n-ffmpeg-7.1-bin" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "bin", - "path": "/nix/store/d1lv3x7iq129vb19ba9ph6k0yhy4fv34-ffmpeg-7.1-bin", - "default": true - }, - { - "name": "man", - "path": "/nix/store/qqgvvfw2gqp47zl5v9jhdsl8mb77l909-ffmpeg-7.1-man", - "default": true - }, - { - "name": "doc", - "path": "/nix/store/gmfj9af6za9i2830cgbj1qazz2nir2vs-ffmpeg-7.1-doc" - }, - { - "name": "lib", - "path": "/nix/store/x8j2nr5qmikfaggl34wpm1dlldb7ik06-ffmpeg-7.1-lib" - }, - { - "name": "out", - "path": "/nix/store/cx89mypnxgk0q4dibacg7dsrb4w66mv9-ffmpeg-7.1" - }, - { - "name": "data", - "path": "/nix/store/5y8zk8fqpaammsnz2svgpdsayn4zlsn2-ffmpeg-7.1-data" - }, - { - "name": "dev", - "path": "/nix/store/qdz8aidi7rksr4g5cpxgz9iivrlsa247-ffmpeg-7.1-dev" - } - ], - "store_path": "/nix/store/d1lv3x7iq129vb19ba9ph6k0yhy4fv34-ffmpeg-7.1-bin" - } - } - }, - "ggshield@latest": { - "last_modified": "2025-02-27T15:48:43Z", - "resolved": "github:NixOS/nixpkgs/6c5c5f5100281f8f4ff23f13edd17d645178c87c#ggshield", - "source": "devbox-search", - "version": "1.36.0", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/2qsc4iii58gq54l8dys7m4jw5lz0xqk0-ggshield-1.36.0", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/1zic4rm52c81303axs6jwpv9i5cbpgpf-ggshield-1.36.0-dist" - } - ], - "store_path": "/nix/store/2qsc4iii58gq54l8dys7m4jw5lz0xqk0-ggshield-1.36.0" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/l9inx1qgmjm9hiz1fncxx15mkyqw9abc-ggshield-1.36.0", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/1hls55sak8fi14s6wq4ar5iiwvmzpw68-ggshield-1.36.0-dist" - } - ], - "store_path": "/nix/store/l9inx1qgmjm9hiz1fncxx15mkyqw9abc-ggshield-1.36.0" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/n2s11c74rlq64w78rnnnz5j8dz72fnvs-ggshield-1.36.0", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/9k2svwlyx8s2ac6dnhc3sq5c3bvlyrvw-ggshield-1.36.0-dist" - } - ], - "store_path": "/nix/store/n2s11c74rlq64w78rnnnz5j8dz72fnvs-ggshield-1.36.0" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/pz8s8n5qrmhfivj51932s5gqwh64c7fy-ggshield-1.36.0", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/i29ambqhmnizdxk9njgsyza953m5mbmn-ggshield-1.36.0-dist" - } - ], - "store_path": "/nix/store/pz8s8n5qrmhfivj51932s5gqwh64c7fy-ggshield-1.36.0" - } - } - }, - "git-subrepo@latest": { - "last_modified": "2025-02-07T11:26:36Z", - "resolved": "github:NixOS/nixpkgs/d98abf5cf5914e5e4e9d57205e3af55ca90ffc1d#git-subrepo", - "source": "devbox-search", - "version": "0.4.9", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/iagwf8k53inahcs16by5l7vzffbs01k4-git-subrepo-0.4.9", - "default": true - } - ], - "store_path": "/nix/store/iagwf8k53inahcs16by5l7vzffbs01k4-git-subrepo-0.4.9" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vn5qc1h596hj3s7qw1q75wzh8n8lw3im-git-subrepo-0.4.9", - "default": true - } - ], - "store_path": "/nix/store/vn5qc1h596hj3s7qw1q75wzh8n8lw3im-git-subrepo-0.4.9" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/pxhc909zdsd1jxamzy762xhvvdh0lb5a-git-subrepo-0.4.9", - "default": true - } - ], - "store_path": "/nix/store/pxhc909zdsd1jxamzy762xhvvdh0lb5a-git-subrepo-0.4.9" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/psy4x285pc5dk3z69gzwq7rafdhpjv5x-git-subrepo-0.4.9", - "default": true - } - ], - "store_path": "/nix/store/psy4x285pc5dk3z69gzwq7rafdhpjv5x-git-subrepo-0.4.9" - } - } - }, - "github:NixOS/nixpkgs/nixpkgs-unstable": { - "resolved": "github:NixOS/nixpkgs/ba0939c506a03c60a765cd7f7c43794816540eec?lastModified=1739482815&narHash=sha256-%2F5Lwtmp%2F8j%2Bro32gXzitucSdyjJ6QehfJCL58WNA7N0%3D" - }, - "lazydocker@latest": { - "last_modified": "2024-12-23T21:10:33Z", - "resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#lazydocker", - "source": "devbox-search", - "version": "0.24.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5hv519gz95pwhg4vr9ka8g98bdd91mvx-lazydocker-0.24.1", - "default": true - } - ], - "store_path": "/nix/store/5hv519gz95pwhg4vr9ka8g98bdd91mvx-lazydocker-0.24.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5wb57rjn6xwyf4nc0mifgjd934i545ph-lazydocker-0.24.1", - "default": true - } - ], - "store_path": "/nix/store/5wb57rjn6xwyf4nc0mifgjd934i545ph-lazydocker-0.24.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bj056q5lmy3dx6xafwlmvhjqgxjr3awq-lazydocker-0.24.1", - "default": true - } - ], - "store_path": "/nix/store/bj056q5lmy3dx6xafwlmvhjqgxjr3awq-lazydocker-0.24.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4gwbhlb13pvdbxcb31mslkgd6pr62gyk-lazydocker-0.24.1", - "default": true - } - ], - "store_path": "/nix/store/4gwbhlb13pvdbxcb31mslkgd6pr62gyk-lazydocker-0.24.1" - } - } - }, - "nodejs@20": { - "last_modified": "2024-12-23T21:10:33Z", - "plugin_version": "0.0.2", - "resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#nodejs_20", - "source": "devbox-search", - "version": "20.18.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/q49zbi0pzjhg4zn085h9hyz9m1k3hvpb-nodejs-20.18.1", - "default": true - }, - { - "name": "libv8", - "path": "/nix/store/l08rljd2yr7i1q4x778qazcys2l4ja23-nodejs-20.18.1-libv8" - } - ], - "store_path": "/nix/store/q49zbi0pzjhg4zn085h9hyz9m1k3hvpb-nodejs-20.18.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4m1ql1hsd6kqmzr8a657qhipjgssrr0c-nodejs-20.18.1", - "default": true - }, - { - "name": "libv8", - "path": "/nix/store/r8s1xalb4rpy1r44i413j84i4ny6mnsc-nodejs-20.18.1-libv8" - } - ], - "store_path": "/nix/store/4m1ql1hsd6kqmzr8a657qhipjgssrr0c-nodejs-20.18.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7ky0mn6k33731jwzhsxq6a6dsbjqamqs-nodejs-20.18.1", - "default": true - }, - { - "name": "libv8", - "path": "/nix/store/jw62k3wxl38r8fcbvxaxrm696ivv3imr-nodejs-20.18.1-libv8" - } - ], - "store_path": "/nix/store/7ky0mn6k33731jwzhsxq6a6dsbjqamqs-nodejs-20.18.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/j7dx1n6m5axf9r2bvly580x2ixx546wq-nodejs-20.18.1", - "default": true - }, - { - "name": "libv8", - "path": "/nix/store/qljmc2skrldj0g94rib6nl4jq84193fa-nodejs-20.18.1-libv8" - } - ], - "store_path": "/nix/store/j7dx1n6m5axf9r2bvly580x2ixx546wq-nodejs-20.18.1" - } - } - }, - "opentofu@latest": { - "last_modified": "2025-02-07T11:26:36Z", - "resolved": "github:NixOS/nixpkgs/d98abf5cf5914e5e4e9d57205e3af55ca90ffc1d#opentofu", - "source": "devbox-search", - "version": "1.9.0", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bk8lbpai9gckl24971cd7sy86nx65vqp-opentofu-1.9.0", - "default": true - } - ], - "store_path": "/nix/store/bk8lbpai9gckl24971cd7sy86nx65vqp-opentofu-1.9.0" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/k56jwj34f3qj0j0q7rsqsnzcvjm83xfb-opentofu-1.9.0", - "default": true - } - ], - "store_path": "/nix/store/k56jwj34f3qj0j0q7rsqsnzcvjm83xfb-opentofu-1.9.0" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/q8a4niqvlph0gbch407q19v444qyflpi-opentofu-1.9.0", - "default": true - } - ], - "store_path": "/nix/store/q8a4niqvlph0gbch407q19v444qyflpi-opentofu-1.9.0" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1gc7dl8bcrks1y98qlblr08aly4b3qry-opentofu-1.9.0", - "default": true - } - ], - "store_path": "/nix/store/1gc7dl8bcrks1y98qlblr08aly4b3qry-opentofu-1.9.0" - } - } - }, - "python310@latest": { - "last_modified": "2025-02-07T11:26:36Z", - "plugin_version": "0.0.4", - "resolved": "github:NixOS/nixpkgs/d98abf5cf5914e5e4e9d57205e3af55ca90ffc1d#python310", - "source": "devbox-search", - "version": "3.10.16", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/n3bv4blh1n8xcswpn23d8rkdf19z1z67-python3-3.10.16", - "default": true - } - ], - "store_path": "/nix/store/n3bv4blh1n8xcswpn23d8rkdf19z1z67-python3-3.10.16" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wdkg0yc6h9fwvvqwh3zss1a2rz4mrmgl-python3-3.10.16", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/wxnpshdg4kbdmpl44qnqx29i0pszsa7f-python3-3.10.16-debug" - } - ], - "store_path": "/nix/store/wdkg0yc6h9fwvvqwh3zss1a2rz4mrmgl-python3-3.10.16" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/40lamqbgh1g2x9mml635n329h4gh1928-python3-3.10.16", - "default": true - } - ], - "store_path": "/nix/store/40lamqbgh1g2x9mml635n329h4gh1928-python3-3.10.16" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8757y4bf8d77z7c3pjz1nlwi2xlkk93h-python3-3.10.16", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/4rj9krr4hgv14rjlsrlajksi580fg4np-python3-3.10.16-debug" - } - ], - "store_path": "/nix/store/8757y4bf8d77z7c3pjz1nlwi2xlkk93h-python3-3.10.16" - } - } - }, - "python310Packages.pip@latest": { - "last_modified": "2023-12-13T22:54:10Z", - "resolved": "github:NixOS/nixpkgs/fd04bea4cbf76f86f244b9e2549fca066db8ddff#python310Packages.pip", - "source": "devbox-search", - "version": "23.2.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vjyrxbxqsadvr9g6mzig6y406dhwcrqi-python3.10-pip-23.2.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/2ra46imgas5srgxx8mgs424akh5j1msv-python3.10-pip-23.2.1-man", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/xjj6xjh21k08rkyg6hnkbyrygqhqgn8y-python3.10-pip-23.2.1-dist" - } - ], - "store_path": "/nix/store/vjyrxbxqsadvr9g6mzig6y406dhwcrqi-python3.10-pip-23.2.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/j8pxwv7vyjm8z2fqglijjvabbkmxbv9r-python3.10-pip-23.2.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/bcfliw00z123ddyi8hsfxvfn2npdcpdq-python3.10-pip-23.2.1-man", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/2326b2sr9p2z9bsghd2pzs346g2qjn7f-python3.10-pip-23.2.1-dist" - } - ], - "store_path": "/nix/store/j8pxwv7vyjm8z2fqglijjvabbkmxbv9r-python3.10-pip-23.2.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7lyvqf8wl47wzgsqmlcz39ycmwxyg9zx-python3.10-pip-23.2.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/0j02s5hbsdhfxvvay5dm9j68nhalm39v-python3.10-pip-23.2.1-man", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/8dvqh9ai83lqaaixs3bhmf1n4jxgp4v7-python3.10-pip-23.2.1-dist" - } - ], - "store_path": "/nix/store/7lyvqf8wl47wzgsqmlcz39ycmwxyg9zx-python3.10-pip-23.2.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/gdhvfi5zaqzpa5l3kk0spmv71r549slf-python3.10-pip-23.2.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/p37y2fhm6l3nd624jmr2r680wf4p0544-python3.10-pip-23.2.1-man", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/r4qj7psryk532rkh0srhn25ygv8yk541-python3.10-pip-23.2.1-dist" - } - ], - "store_path": "/nix/store/gdhvfi5zaqzpa5l3kk0spmv71r549slf-python3.10-pip-23.2.1" - } - } - }, - "yt-dlp@latest": { - "last_modified": "2025-01-03T14:51:55Z", - "resolved": "github:NixOS/nixpkgs/a27871180d30ebee8aa6b11bf7fef8a52f024733#yt-dlp", - "source": "devbox-search", - "version": "2024.12.23", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8fmy039278i7q31zyyrfmr4z5k35xvp6-yt-dlp-2024.12.23", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/v9mplambvs7hlcpcpnvmf7c30pk5cx8d-yt-dlp-2024.12.23-dist" - } - ], - "store_path": "/nix/store/8fmy039278i7q31zyyrfmr4z5k35xvp6-yt-dlp-2024.12.23" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wzna2q40a81qj4icma4q20q9fjg9md76-yt-dlp-2024.12.23", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/z0b0nv6a2wl0565f5ffrzhg2zcqflvrl-yt-dlp-2024.12.23-dist" - } - ], - "store_path": "/nix/store/wzna2q40a81qj4icma4q20q9fjg9md76-yt-dlp-2024.12.23" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/mpbp9jar45hk22ddldm0bbk60vz5w643-yt-dlp-2024.12.23", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/gq4l9yfs7fjb05qkl97hmsq69s3k4shr-yt-dlp-2024.12.23-dist" - } - ], - "store_path": "/nix/store/mpbp9jar45hk22ddldm0bbk60vz5w643-yt-dlp-2024.12.23" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wqcs5crm36p603fkh9j2k868zzb8q79c-yt-dlp-2024.12.23", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/j452c5bii2slx1biix7lfc5k0aqg2rvs-yt-dlp-2024.12.23-dist" - } - ], - "store_path": "/nix/store/wqcs5crm36p603fkh9j2k868zzb8q79c-yt-dlp-2024.12.23" - } - } - } - } -} diff --git a/package.json b/package.json index a0cd88b..f95da51 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,12 @@ "keywords": [], "author": "@CJ_Clippy", "license": "Unlicense", - "packageManager": "pnpm@9.6.0", "dependencies": { "chokidar-cli": "^3.0.0", "types": "^0.1.1" }, "devDependencies": { "concurrently": "^8.2.2" - } + }, + "packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad" } diff --git a/services/our/.dockerignore b/services/our/.dockerignore index 9a0ca6a..d007df5 100644 --- a/services/our/.dockerignore +++ b/services/our/.dockerignore @@ -1,3 +1,6 @@ +runs +requirements.txt +venv src/test node_modules diff --git a/services/our/.gitignore b/services/our/.gitignore index 209904f..19c3c96 100644 --- a/services/our/.gitignore +++ b/services/our/.gitignore @@ -1,3 +1,5 @@ +runs +venv vibeui generated diff --git a/services/our/package.json b/services/our/package.json index 9d18cd4..810b884 100644 --- a/services/our/package.json +++ b/services/our/package.json @@ -58,6 +58,7 @@ "@types/node": "^22.16.3", "@types/node-fetch": "^2.6.12", "cache-manager": "^7.0.1", + "canvas": "^3.1.2", "chokidar-cli": "^3.0.0", "concurrently": "^9.2.0", "date-fns": "^4.1.0", @@ -77,6 +78,7 @@ "nanoid": "^5.1.5", "node-fetch": "^3.3.2", "onnxruntime-node": "1.22.0-rev", + "protobufjs": "^7.5.3", "rate-limiter-flexible": "^7.1.1", "rimraf": "6.0.1", "sharp": "^0.34.3", diff --git a/services/our/pnpm-lock.yaml b/services/our/pnpm-lock.yaml index 62ae16d..326a139 100644 --- a/services/our/pnpm-lock.yaml +++ b/services/our/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: cache-manager: specifier: ^7.0.1 version: 7.0.1 + canvas: + specifier: ^3.1.2 + version: 3.1.2 chokidar-cli: specifier: ^3.0.0 version: 3.0.0 @@ -128,6 +131,9 @@ importers: onnxruntime-node: specifier: 1.22.0-rev version: 1.22.0-rev + protobufjs: + specifier: ^7.5.3 + version: 7.5.3 rate-limiter-flexible: specifier: ^7.1.1 version: 7.1.1 @@ -956,6 +962,36 @@ packages: '@prisma/get-platform@6.8.2': resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@rollup/rollup-android-arm-eabi@4.45.1': resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} cpu: [arm] @@ -1640,6 +1676,10 @@ packages: canvas-renderer@2.2.1: resolution: {integrity: sha512-RrBgVL5qCEDIXpJ6NrzyRNoTnXxYarqm/cS/W6ERhUJts5UQtt/XPEosGN3rqUkZ4fjBArlnCbsISJ+KCFnIAg==} + canvas@3.1.2: + resolution: {integrity: sha512-Z/tzFAcBzoCvJlOSlCnoekh1Gu8YMn0J51+UAuXJAbW1Z6I9l2mZgdD7738MepoeeIcUdDtbMnOg6cC7GJxy/g==} + engines: {node: ^18.12.0 || >= 20.9.0} + chai@5.2.1: resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} engines: {node: '>=18'} @@ -2427,6 +2467,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loupe@3.1.4: resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} @@ -2563,6 +2606,9 @@ packages: node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-addon-api@8.5.0: resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} engines: {node: ^18 || ^20 || >= 21} @@ -2868,6 +2914,10 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + protobufjs@7.5.3: + resolution: {integrity: sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==} + engines: {node: '>=12.0.0'} + pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} @@ -4645,6 +4695,29 @@ snapshots: dependencies: '@prisma/debug': 6.8.2 + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@rollup/rollup-android-arm-eabi@4.45.1': optional: true @@ -5422,6 +5495,11 @@ snapshots: dependencies: '@types/node': 22.16.4 + canvas@3.1.2: + dependencies: + node-addon-api: 7.1.1 + prebuild-install: 7.1.3 + chai@5.2.1: dependencies: assertion-error: 2.0.1 @@ -6289,6 +6367,8 @@ snapshots: lodash@4.17.21: {} + long@5.3.2: {} + loupe@3.1.4: {} lru-cache@10.4.3: {} @@ -6396,6 +6476,8 @@ snapshots: node-addon-api@6.1.0: {} + node-addon-api@7.1.1: {} + node-addon-api@8.5.0: {} node-domexception@1.0.0: {} @@ -6686,6 +6768,21 @@ snapshots: process-warning@5.0.0: {} + protobufjs@7.5.3: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 22.16.4 + long: 5.3.2 + pstree.remy@1.1.8: {} pump@3.0.3: diff --git a/services/our/requirements.txt b/services/our/requirements.txt new file mode 100644 index 0000000..c6856f7 --- /dev/null +++ b/services/our/requirements.txt @@ -0,0 +1 @@ +ultralytics \ No newline at end of file diff --git a/services/our/src/config/env.ts b/services/our/src/config/env.ts index bb2d8f7..8b803a8 100644 --- a/services/our/src/config/env.ts +++ b/services/our/src/config/env.ts @@ -8,6 +8,7 @@ dotenvx.config({ path: ['../../.env.development'] }) const EnvSchema = z.object({ NODE_ENV: z.enum(['development', 'production', 'test']), + VENV: z.string(), PORT: z.coerce.number().default(3000), DATABASE_URL: z.string().url(), ORIGIN: z.string(), @@ -27,6 +28,7 @@ const EnvSchema = z.object({ CDN_TOKEN_SECRET: z.string(), CACHE_ROOT: z.string().default('/tmp/our'), VIBEUI_DIR: z.string().default('/opt/futureporn/apps/vibeui'), + APP_DIR: z.string().default('/app') }); const parsed = EnvSchema.safeParse(process.env); diff --git a/services/our/src/tasks/createFunscript.ts.old b/services/our/src/tasks/createFunscript copy.ts.noexec similarity index 90% rename from services/our/src/tasks/createFunscript.ts.old rename to services/our/src/tasks/createFunscript copy.ts.noexec index 7ce2422..787d69d 100644 --- a/services/our/src/tasks/createFunscript.ts.old +++ b/services/our/src/tasks/createFunscript copy.ts.noexec @@ -60,48 +60,48 @@ async function loadDataYaml(yamlPath: string): Promise { } -// async function preparePython(helpers) { -// const spawn = await getNanoSpawn(); -// const venvPath = join(env.VIBEUI_DIR, "venv"); +async function preparePython(helpers) { + const spawn = await getNanoSpawn(); + const venvPath = join(env.VIBEUI_DIR, "venv"); -// // Determine Python executable -// let pythonCmd; -// try { -// pythonCmd = which.sync("python3"); -// } catch { -// helpers.logger.error("Python is not installed or not in PATH."); -// throw new Error("Python not found in PATH."); -// } + // Determine Python executable + let pythonCmd; + try { + pythonCmd = which.sync("python3"); + } catch { + helpers.logger.error("Python is not installed or not in PATH."); + throw new Error("Python not found in PATH."); + } -// // If venv doesn't exist, create it -// if (!existsSync(venvPath)) { -// helpers.logger.info("Python venv not found. Creating one..."); + // If venv doesn't exist, create it + if (!existsSync(venvPath)) { + helpers.logger.info("Python venv not found. Creating one..."); -// try { -// await spawn(pythonCmd, ["-m", "venv", "venv"], { -// cwd: env.VIBEUI_DIR, -// }); + try { + await spawn(pythonCmd, ["-m", "venv", "venv"], { + cwd: env.VIBEUI_DIR, + }); -// helpers.logger.info("Python venv successfully created."); -// } catch (err) { -// helpers.logger.error("Failed to create Python venv:", err); + helpers.logger.info("Python venv successfully created."); + } catch (err) { + helpers.logger.error("Failed to create Python venv:", err); -// // Clean up partially created venv if needed -// try { -// if (existsSync(venvPath)) { -// rmSync(venvPath, { recursive: true, force: true }); -// helpers.logger.warn("Removed broken venv directory."); -// } -// } catch (cleanupErr) { -// helpers.logger.error("Error while cleaning up broken venv:", cleanupErr); -// } + // Clean up partially created venv if needed + try { + if (existsSync(venvPath)) { + rmSync(venvPath, { recursive: true, force: true }); + helpers.logger.warn("Removed broken venv directory."); + } + } catch (cleanupErr) { + helpers.logger.error("Error while cleaning up broken venv:", cleanupErr); + } -// throw new Error("Python venv creation failed. Check if python3 and python3-venv are installed."); -// } -// } else { -// helpers.logger.info("Using existing Python venv."); -// } -// } + throw new Error("Python venv creation failed. Check if python3 and python3-venv are installed."); + } + } else { + helpers.logger.info("Using existing Python venv."); + } +} async function ffprobe(videoPath: string): Promise<{ fps: number; frames: number }> { diff --git a/services/our/src/tasks/createFunscript.ts b/services/our/src/tasks/createFunscript.ts index 95da0f0..ccaa5fe 100644 --- a/services/our/src/tasks/createFunscript.ts +++ b/services/our/src/tasks/createFunscript.ts @@ -1,18 +1,54 @@ - import type { Task, Helpers } from "graphile-worker"; import { PrismaClient } from "../../generated/prisma"; import { withAccelerate } from "@prisma/extension-accelerate"; import { getOrDownloadAsset } from "../utils/cache"; import { env } from "../config/env"; import { getS3Client, uploadFile } from "../utils/s3"; -import { buildFunscript } from '../utils/funscripts'; -import { vibeuiInference } from "../utils/vibeui"; -import { join } from "node:path"; +import { nanoid } from "nanoid"; +import { existsSync, rmSync } from "node:fs"; +import { join, basename, extname } from "node:path"; +import { readFile, writeFile, readdir } from 'node:fs/promises'; +import yaml from 'js-yaml'; +import { getNanoSpawn } from "../utils/nanoSpawn"; +import which from "which"; +import * as ort from 'onnxruntime-node'; +import { inference, loadDataYaml } from "../utils/vibeui"; +import { ffprobe } from "../utils/vibeui"; +import { preparePython } from "../utils/python"; +import { generateActions2, buildFunscript } from "../utils/funscripts"; + interface Payload { vodId: string; } +// interface Detection { +// startFrame: number; +// endFrame: number; +// className: string; +// } + +// interface DataYaml { +// path: string; +// train: string; +// val: string; +// names: Record; +// } + +// interface FunscriptAction { +// at: number; +// pos: number; +// } + +// interface Funscript { +// version: string; +// actions: FunscriptAction[]; +// } + + +// interface ClassPositionMap { +// [className: string]: number | 'pattern'; +// } const prisma = new PrismaClient().$extends(withAccelerate()); @@ -24,6 +60,209 @@ function assertPayload(payload: any): asserts payload is Payload { } + + + +// export async function buildFunscript( +// helpers: Helpers, +// predictionOutput: string, +// videoPath: string +// ): Promise { +// const labelDir = join(predictionOutput, 'labels'); +// const yamlPath = join(predictionOutput, 'data.yaml'); +// const outputPath = join(process.env.CACHE_ROOT ?? '/tmp', `${nanoid()}.funscript`); +// helpers.logger.info('Starting Funscript generation'); + +// try { + +// const data = await loadDataYaml(join(env.VIBEUI_DIR, 'data.yaml')) +// const classPositionMap = await loadClassPositionMap(data, helpers); +// const { fps, totalFrames } = await loadVideoMetadata(videoPath, helpers); +// const detectionSegments = await processLabelFiles(labelDir, helpers, data); +// const totalDurationMs = Math.floor((totalFrames / fps) * 1000); +// const actions = generateActions2(totalDurationMs, fps, detectionSegments, classPositionMap); +// await writeFunscript(outputPath, actions, helpers); + +// return outputPath; +// } catch (error) { +// helpers.logger.error(`Error generating Funscript: ${error instanceof Error ? error.message : 'Unknown error'}`); +// throw error; +// } +// } + + + +// async function loadClassPositionMap(data: DataYaml, helpers: Helpers): Promise { +// try { + +// if ( +// !data || +// typeof data !== 'object' || +// !('names' in data) || +// typeof data.names !== 'object' || +// data.names === null || +// Object.keys(data.names).length === 0 +// ) { +// throw new Error('Invalid data.yaml: "names" field is missing, not an object, or empty'); +// } + +// const positionMap: ClassPositionMap = { +// ControlledByTipper: 50, +// ControlledByTipperHigh: 80, +// ControlledByTipperLow: 20, +// ControlledByTipperMedium: 50, +// ControlledByTipperUltrahigh: 95, +// Ring1: 30, +// Ring2: 40, +// Ring3: 50, +// Ring4: 60, +// Earthquake: 'pattern', +// Fireworks: 'pattern', +// Pulse: 'pattern', +// Wave: 'pattern', +// Pause: 0, +// RandomTime: 70, +// HighLevel: 80, +// LowLevel: 20, +// MediumLevel: 50, +// UltraHighLevel: 95 +// }; + +// const names = Object.values(data.names); +// for (const name of names) { +// if (typeof name !== 'string' || name.trim() === '') { +// helpers.logger.info(`Skipping invalid class name: ${name}`); +// continue; +// } +// if (!(name in positionMap)) { +// helpers.logger.info(`No position mapping for class "${name}", defaulting to 0`); +// positionMap[name] = 0; +// } +// } + +// helpers.logger.info(`Loaded class position map: ${JSON.stringify(positionMap)}`); +// return positionMap; +// } catch (error) { +// helpers.logger.error(`Error loading data.yaml: ${error instanceof Error ? error.message : 'Unknown error'}`); +// throw error; +// } +// } + +// function generatePatternPositions(startMs: number, durationMs: number, className: string, fps: number): FunscriptAction[] { +// const actions: FunscriptAction[] = []; +// const frameDurationMs = 1000 / fps; +// const totalFrames = Math.floor(durationMs / frameDurationMs); +// const intervalMs = 100; + +// for (let timeMs = 0; timeMs < durationMs; timeMs += intervalMs) { +// const progress = timeMs / durationMs; +// let pos = 0; + +// switch (className) { +// case 'Pulse': +// pos = Math.round(50 * Math.sin(progress * 2 * Math.PI)); +// break; +// case 'Wave': +// pos = Math.round(50 + 50 * Math.sin(progress * 2 * Math.PI)); +// break; +// case 'Fireworks': +// pos = Math.random() > 0.5 ? 80 : 0; +// break; +// case 'Earthquake': +// pos = Math.round(90 * Math.sin(progress * 4 * Math.PI) + (Math.random() - 0.5) * 10); +// pos = Math.max(0, Math.min(90, pos)); +// break; +// } + +// actions.push({ at: startMs + timeMs, pos }); +// } + +// return actions; +// } + +// async function loadVideoMetadata(videoPath: string, helpers: Helpers) { +// const { fps, frames: totalFrames } = await ffprobe(videoPath); +// helpers.logger.info(`Video metadata: fps=${fps}, frames=${totalFrames}`); +// return { fps, totalFrames }; +// } + + +// async function processLabelFiles(labelDir: string, helpers: Helpers, data: DataYaml): Promise { +// const labelFiles = (await readdir(labelDir)).filter(file => file.endsWith('.txt')); +// const detections: Map = new Map(); +// const names = data.names; + +// for (const file of labelFiles) { +// const match = file.match(/(\d+)\.txt$/); +// if (!match) { +// helpers.logger.info(`Skipping invalid filename: ${file}`); +// continue; +// } +// const frameIndex = parseInt(match[1], 10); +// if (isNaN(frameIndex)) { +// helpers.logger.info(`Skipping invalid frame index from filename: ${file}`); +// continue; +// } + +// const content = await readFile(join(labelDir, file), 'utf8'); +// const lines = content.trim().split('\n'); +// const frameDetections: Detection[] = []; +// let maxConfidence = 0; +// let selectedClassIndex = -1; + +// for (const line of lines) { +// const parts = line.trim().split(/\s+/); +// if (parts.length < 6) continue; + +// const classIndex = parseInt(parts[0], 10); +// const confidence = parseFloat(parts[5]); +// if (isNaN(classIndex) || isNaN(confidence)) continue; + +// if (confidence >= 0.7 && confidence > maxConfidence) { +// maxConfidence = confidence; +// selectedClassIndex = classIndex; +// } +// } + +// if (maxConfidence > 0) { +// const className = (data.names as Record)[selectedClassIndex.toString()]; +// if (className) { +// frameDetections.push({ startFrame: frameIndex, endFrame: frameIndex, className }); +// } +// } + +// if (frameDetections.length > 0) { +// detections.set(frameIndex, frameDetections); +// } +// } + +// // Merge overlapping detections into continuous segments +// const detectionSegments: Detection[] = []; +// let currentDetection: Detection | null = null; + +// for (const [frameIndex, frameDetections] of detections.entries()) { +// for (const detection of frameDetections) { +// if (!currentDetection || currentDetection.className !== detection.className) { +// if (currentDetection) detectionSegments.push(currentDetection); +// currentDetection = { ...detection, endFrame: frameIndex }; +// } else { +// currentDetection.endFrame = frameIndex; +// } +// } +// } +// if (currentDetection) detectionSegments.push(currentDetection); + +// return detectionSegments; +// } + + +// async function writeFunscript(outputPath: string, actions: FunscriptAction[], helpers: Helpers) { +// const funscript: Funscript = { version: '1.0', actions }; +// await writeFile(outputPath, JSON.stringify(funscript, null, 2)); +// helpers.logger.info(`Funscript generated: ${outputPath} (${actions.length} actions)`); +// } + + const createFunscript: Task = async (payload: any, helpers: Helpers) => { assertPayload(payload); const { vodId } = payload; @@ -31,6 +270,7 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => { const vod = await prisma.vod.findFirstOrThrow({ where: { id: vodId } }); + await preparePython() if (vod.funscript) { helpers.logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`); @@ -51,12 +291,11 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => { helpers.logger.info(`Creating funscript for vod ${vodId}...`); - const modelPath = join(env.VIBEUI_DIR, 'vibeui.onnx') - const predictionOutput = await vibeuiInference(modelPath, videoFilePath); - helpers.logger.info(`prediction output ${predictionOutput}`); + const predictionOutputPath = await inference(videoFilePath); + helpers.logger.info(`prediction output ${predictionOutputPath}`); - const funscriptFilePath = await buildFunscript(predictionOutput, videoFilePath) + const funscriptFilePath = await buildFunscript(predictionOutputPath, videoFilePath) const s3Key = `funscripts/${vodId}.funscript`; diff --git a/services/our/src/tasks/createFunscript.ts.ai.noexec b/services/our/src/tasks/createFunscript.ts.ai.noexec new file mode 100644 index 0000000..cf5ab17 --- /dev/null +++ b/services/our/src/tasks/createFunscript.ts.ai.noexec @@ -0,0 +1,75 @@ + +import type { Task, Helpers } from "graphile-worker"; +import { PrismaClient } from "../../generated/prisma"; +import { withAccelerate } from "@prisma/extension-accelerate"; +import { getOrDownloadAsset } from "../utils/cache"; +import { env } from "../config/env"; +import { getS3Client, uploadFile } from "../utils/s3"; +import { buildFunscript } from '../utils/funscripts'; +import { getModelClasses, vibeuiInference } from "../utils/vibeui"; +import { join } from "node:path"; + +interface Payload { + vodId: string; +} + + + +const prisma = new PrismaClient().$extends(withAccelerate()); + + +function assertPayload(payload: any): asserts payload is Payload { + if (typeof payload !== "object" || !payload) throw new Error("invalid payload-- was not an object."); + if (typeof payload.vodId !== "string") throw new Error("invalid payload-- was missing vodId"); +} + + +const createFunscript: Task = async (payload: any, helpers: Helpers) => { + assertPayload(payload); + const { vodId } = payload; + + + + const vod = await prisma.vod.findFirstOrThrow({ where: { id: vodId } }); + + if (vod.funscript) { + helpers.logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`); + return; + } + + if (!vod.sourceVideo) { + const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`; + helpers.logger.warn(msg); + throw new Error(msg); + } + + + + const s3Client = getS3Client(); + const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo); + helpers.logger.info(`Downloaded video to ${videoFilePath}`); + + helpers.logger.info(`Creating funscript for vod ${vodId}...`); + + const modelPath = join(env.VIBEUI_DIR, 'vibeui.onnx') + const predictionOutput = await vibeuiInference(modelPath, videoFilePath); + helpers.logger.info(`prediction output ${predictionOutput}`); + const classes = await getModelClasses(modelPath) + + const funscriptFilePath = await buildFunscript(classes, predictionOutput, videoFilePath) + + + const s3Key = `funscripts/${vodId}.funscript`; + const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json"); + + helpers.logger.info(`Uploaded funscript to S3: ${s3Url}`); + + await prisma.vod.update({ + where: { id: vodId }, + data: { funscript: s3Key } + }); + + helpers.logger.info(`Funscript saved to database for vod ${vodId}`); +}; + +export default createFunscript; diff --git a/services/our/src/tests/createFunscript.integration.test.ts b/services/our/src/tests/createFunscript.integration.test.ts new file mode 100644 index 0000000..b3c0899 --- /dev/null +++ b/services/our/src/tests/createFunscript.integration.test.ts @@ -0,0 +1,141 @@ + +import { describe, it, expect, beforeAll } from 'vitest'; +import { join } from 'node:path'; +import { readdir, readFile } from 'node:fs/promises'; +import { loadDataYaml, loadVideoMetadata, inference } from '../utils/vibeui'; +import { env } from '../config/env'; +import { DataYaml, writeFunscript, generateActions1, classPositionMap, buildFunscript } from '../utils/funscripts'; +import { nanoid } from 'nanoid'; +import { getNanoSpawn } from '../utils/nanoSpawn'; +import { preparePython } from '../utils/python'; + +interface Detection { + startFrame: number; + endFrame: number; + className: string; +} + + +const __dirname = import.meta.dirname; + +const fixturesDir = join(__dirname, '..', 'tests', 'fixtures') +const sampleVideoPath = join(fixturesDir, 'sample.mp4') + + +/** + * Processes YOLO label files and constructs time-aligned detection segments. + * + * - Reads all `.txt` label files from a directory, one per video frame. + * - Parses bounding box class indices and confidence scores. + * - Selects the most confident detection per frame above a confidence threshold (0.7). + * - Maps class indices to class names using the provided `data.yaml`. + * - Groups consecutive frames with the same class into continuous detection segments. + * + * @param labelDir - Path to the directory containing YOLO label `.txt` files. + * @param data - Parsed data.yaml object containing class name mappings. + * @returns An array of merged `Detection` objects with start and end frame ranges. + * @throws If file reading or parsing fails. + */ +async function processLabelFiles(labelDir: string, data: DataYaml): Promise { + const labelFiles = (await readdir(labelDir)).filter(file => file.endsWith('.txt')); + console.log("Label files found:", labelFiles); + const detections: Map = new Map(); + const names = data.names; + + for (const file of labelFiles) { + const match = file.match(/(\d+)\.txt$/); + if (!match) { + console.log(`Skipping invalid filename: ${file}`); + continue; + } + const frameIndex = parseInt(match[1], 10); + if (isNaN(frameIndex)) { + console.log(`Skipping invalid frame index from filename: ${file}`); + continue; + } + + const content = await readFile(join(labelDir, file), 'utf8'); + const lines = content.trim().split('\n'); + const frameDetections: Detection[] = []; + let maxConfidence = 0; + let selectedClassIndex = -1; + + for (const line of lines) { + const parts = line.trim().split(/\s+/); + if (parts.length < 6) continue; + + const classIndex = parseInt(parts[0], 10); + const confidence = parseFloat(parts[5]); + if (isNaN(classIndex) || isNaN(confidence)) continue; + + if (confidence >= 0.7 && confidence > maxConfidence) { + maxConfidence = confidence; + selectedClassIndex = classIndex; + } + } + + if (maxConfidence > 0) { + const className = (data.names as Record)[selectedClassIndex.toString()]; + if (className) { + frameDetections.push({ startFrame: frameIndex, endFrame: frameIndex, className }); + } + } + + if (frameDetections.length > 0) { + detections.set(frameIndex, frameDetections); + } + } + + // Merge overlapping detections into continuous segments + const detectionSegments: Detection[] = []; + let currentDetection: Detection | null = null; + + for (const [frameIndex, frameDetections] of detections.entries()) { + for (const detection of frameDetections) { + if (!currentDetection || currentDetection.className !== detection.className) { + if (currentDetection) detectionSegments.push(currentDetection); + currentDetection = { ...detection, endFrame: frameIndex }; + } else { + currentDetection.endFrame = frameIndex; + } + } + } + if (currentDetection) detectionSegments.push(currentDetection); + + return detectionSegments; +} + + + + + +describe('createFunscript', () => { + + let predictionOutputPath: string + + beforeAll(async () => { + predictionOutputPath = await inference(sampleVideoPath) + }, 35_000) + + it('should contain positions other than 0', async () => { + + + const videoPath = join(__dirname, 'fixtures', 'sample.mp4'); + + const funscriptPath = await buildFunscript(predictionOutputPath, videoPath); + console.log(`built funscript at ${funscriptPath}`) + + + const content = JSON.parse(await readFile(funscriptPath, 'utf8') as string); + + expect(content).toHaveProperty('version', '1.0'); + expect(Array.isArray(content.actions)).toBe(true); + + const allPosZero = content.actions.every((a: any) => a.pos === 0); + expect(allPosZero).toBe(false); // if this fails, it means the funscript did not generate position values that map to the various detected classes + + expect(content.actions.length).toBeGreaterThan(0); + }) + + +}) \ No newline at end of file diff --git a/services/our/src/tests/fixtures/data.yaml b/services/our/src/tests/data.yaml similarity index 100% rename from services/our/src/tests/fixtures/data.yaml rename to services/our/src/tests/data.yaml diff --git a/services/our/src/tests/fixtures/prediction/labels/1.txt b/services/our/src/tests/fixtures/prediction/labels/1.txt deleted file mode 100644 index b1d4a41..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/1.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.038431 0.089941 0.063310 0.075142 53.145020 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/10.txt b/services/our/src/tests/fixtures/prediction/labels/10.txt deleted file mode 100644 index b5602a0..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/10.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.038782 0.087836 0.061486 0.073967 52.052288 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/100.txt b/services/our/src/tests/fixtures/prediction/labels/100.txt deleted file mode 100644 index 38dad46..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/100.txt +++ /dev/null @@ -1 +0,0 @@ -56 0.035719 0.076428 0.052471 0.062387 45.073280 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/101.txt b/services/our/src/tests/fixtures/prediction/labels/101.txt deleted file mode 100644 index 689eab7..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/101.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.035468 0.077997 0.051584 0.064488 45.364609 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/102.txt b/services/our/src/tests/fixtures/prediction/labels/102.txt deleted file mode 100644 index c068591..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/102.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.037174 0.075309 0.052773 0.061913 42.606949 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/103.txt b/services/our/src/tests/fixtures/prediction/labels/103.txt deleted file mode 100644 index 4a7839a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/103.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.036868 0.075512 0.051822 0.062220 42.845398 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/104.txt b/services/our/src/tests/fixtures/prediction/labels/104.txt deleted file mode 100644 index d5a8317..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/104.txt +++ /dev/null @@ -1 +0,0 @@ -58 0.033982 0.077916 0.052823 0.061902 49.985241 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/105.txt b/services/our/src/tests/fixtures/prediction/labels/105.txt deleted file mode 100644 index 9485f59..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/105.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.031318 0.063680 0.047338 0.051505 42.080074 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/106.txt b/services/our/src/tests/fixtures/prediction/labels/106.txt deleted file mode 100644 index 9eb18ef..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/106.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.032635 0.051113 0.043934 0.045176 29.531828 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/107.txt b/services/our/src/tests/fixtures/prediction/labels/107.txt deleted file mode 100644 index 937f351..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/107.txt +++ /dev/null @@ -1 +0,0 @@ -59 0.029333 0.040158 0.037184 0.046115 42.523987 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/108.txt b/services/our/src/tests/fixtures/prediction/labels/108.txt deleted file mode 100644 index 1538b63..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/108.txt +++ /dev/null @@ -1 +0,0 @@ -60 0.023820 0.041723 0.024071 0.052091 51.896393 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/109.txt b/services/our/src/tests/fixtures/prediction/labels/109.txt deleted file mode 100644 index edd340f..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/109.txt +++ /dev/null @@ -1 +0,0 @@ -59 0.028336 0.039560 0.034117 0.048055 45.588940 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/11.txt b/services/our/src/tests/fixtures/prediction/labels/11.txt deleted file mode 100644 index 754f960..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/11.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.040177 0.089766 0.063404 0.075716 52.578529 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/110.txt b/services/our/src/tests/fixtures/prediction/labels/110.txt deleted file mode 100644 index d5e8fe1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/110.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.030120 0.048511 0.038019 0.047205 38.291862 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/111.txt b/services/our/src/tests/fixtures/prediction/labels/111.txt deleted file mode 100644 index 433613d..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/111.txt +++ /dev/null @@ -1 +0,0 @@ -51 0.028028 0.048727 0.035394 0.045787 41.533302 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/112.txt b/services/our/src/tests/fixtures/prediction/labels/112.txt deleted file mode 100644 index 5f7e547..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/112.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.030124 0.056849 0.042351 0.057114 45.306530 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/113.txt b/services/our/src/tests/fixtures/prediction/labels/113.txt deleted file mode 100644 index 5c030d4..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/113.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.031095 0.054593 0.043671 0.062581 45.146286 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/114.txt b/services/our/src/tests/fixtures/prediction/labels/114.txt deleted file mode 100644 index f86440f..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/114.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.032167 0.056456 0.045219 0.064320 46.130051 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/115.txt b/services/our/src/tests/fixtures/prediction/labels/115.txt deleted file mode 100644 index ab2b64d..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/115.txt +++ /dev/null @@ -1 +0,0 @@ -46 0.022684 0.037057 0.020501 0.039577 37.016544 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/116.txt b/services/our/src/tests/fixtures/prediction/labels/116.txt deleted file mode 100644 index 4d51bae..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/116.txt +++ /dev/null @@ -1 +0,0 @@ -44 0.020022 0.036946 0.020763 0.039563 37.264973 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/117.txt b/services/our/src/tests/fixtures/prediction/labels/117.txt deleted file mode 100644 index 8807154..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/117.txt +++ /dev/null @@ -1 +0,0 @@ -46 0.023001 0.038526 0.025594 0.027946 25.011108 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/118.txt b/services/our/src/tests/fixtures/prediction/labels/118.txt deleted file mode 100644 index 928fffd..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/118.txt +++ /dev/null @@ -1 +0,0 @@ -45 0.021071 0.038914 0.026670 0.028368 23.412777 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/119.txt b/services/our/src/tests/fixtures/prediction/labels/119.txt deleted file mode 100644 index 4f6551d..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/119.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.022739 0.043524 0.029497 0.030117 21.047352 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/12.txt b/services/our/src/tests/fixtures/prediction/labels/12.txt deleted file mode 100644 index a8d92d2..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/12.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.038738 0.088193 0.061146 0.073904 52.342270 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/120.txt b/services/our/src/tests/fixtures/prediction/labels/120.txt deleted file mode 100644 index 2c3ce39..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/120.txt +++ /dev/null @@ -1 +0,0 @@ -33 0.023468 0.047506 0.032993 0.033216 22.122324 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/121.txt b/services/our/src/tests/fixtures/prediction/labels/121.txt deleted file mode 100644 index da79eb3..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/121.txt +++ /dev/null @@ -1 +0,0 @@ -29 0.024802 0.050099 0.036248 0.036333 23.996782 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/122.txt b/services/our/src/tests/fixtures/prediction/labels/122.txt deleted file mode 100644 index 59d654b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/122.txt +++ /dev/null @@ -1 +0,0 @@ -27 0.026263 0.054922 0.039299 0.039462 25.030342 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/123.txt b/services/our/src/tests/fixtures/prediction/labels/123.txt deleted file mode 100644 index c53b1bb..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/123.txt +++ /dev/null @@ -1 +0,0 @@ -27 0.027968 0.059208 0.042927 0.041978 26.387854 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/124.txt b/services/our/src/tests/fixtures/prediction/labels/124.txt deleted file mode 100644 index c42c9f1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/124.txt +++ /dev/null @@ -1 +0,0 @@ -27 0.026905 0.057451 0.040628 0.041066 26.058964 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/125.txt b/services/our/src/tests/fixtures/prediction/labels/125.txt deleted file mode 100644 index 64969f2..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/125.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027567 0.057046 0.041958 0.042930 27.190252 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/126.txt b/services/our/src/tests/fixtures/prediction/labels/126.txt deleted file mode 100644 index 4131868..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/126.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027424 0.058000 0.041726 0.043075 27.314507 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/127.txt b/services/our/src/tests/fixtures/prediction/labels/127.txt deleted file mode 100644 index b21cfc1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/127.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027354 0.059303 0.041741 0.043003 27.271029 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/128.txt b/services/our/src/tests/fixtures/prediction/labels/128.txt deleted file mode 100644 index fee2376..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/128.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027216 0.060089 0.041448 0.042873 27.201962 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/129.txt b/services/our/src/tests/fixtures/prediction/labels/129.txt deleted file mode 100644 index 9cbbd6f..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/129.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027259 0.059818 0.041481 0.042875 27.166683 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/13.txt b/services/our/src/tests/fixtures/prediction/labels/13.txt deleted file mode 100644 index dd3f9c0..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/13.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.038905 0.088440 0.061114 0.074878 52.844406 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/130.txt b/services/our/src/tests/fixtures/prediction/labels/130.txt deleted file mode 100644 index 32bf287..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/130.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027364 0.058919 0.041654 0.043002 27.260029 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/131.txt b/services/our/src/tests/fixtures/prediction/labels/131.txt deleted file mode 100644 index c324648..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/131.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027422 0.059680 0.041713 0.043012 27.289568 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/132.txt b/services/our/src/tests/fixtures/prediction/labels/132.txt deleted file mode 100644 index 641675b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/132.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027505 0.060784 0.041890 0.042989 27.195068 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/133.txt b/services/our/src/tests/fixtures/prediction/labels/133.txt deleted file mode 100644 index cfad7df..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/133.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027367 0.061949 0.041727 0.043011 27.209845 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/134.txt b/services/our/src/tests/fixtures/prediction/labels/134.txt deleted file mode 100644 index 86f5737..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/134.txt +++ /dev/null @@ -1 +0,0 @@ -28 0.027787 0.063247 0.042555 0.043069 27.263746 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/135.txt b/services/our/src/tests/fixtures/prediction/labels/135.txt deleted file mode 100644 index fa9b794..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/135.txt +++ /dev/null @@ -1 +0,0 @@ -31 0.029057 0.066847 0.045142 0.044002 27.712589 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/136.txt b/services/our/src/tests/fixtures/prediction/labels/136.txt deleted file mode 100644 index a8cbcb8..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/136.txt +++ /dev/null @@ -1 +0,0 @@ -47 0.038125 0.073041 0.063277 0.069168 46.141243 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/137.txt b/services/our/src/tests/fixtures/prediction/labels/137.txt deleted file mode 100644 index 89cdeb6..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/137.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.038465 0.077648 0.063928 0.070589 47.159187 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/138.txt b/services/our/src/tests/fixtures/prediction/labels/138.txt deleted file mode 100644 index 3af86a1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/138.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.038857 0.077233 0.064686 0.071919 47.977119 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/139.txt b/services/our/src/tests/fixtures/prediction/labels/139.txt deleted file mode 100644 index a859b20..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/139.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.039132 0.078201 0.065272 0.072841 48.427032 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/14.txt b/services/our/src/tests/fixtures/prediction/labels/14.txt deleted file mode 100644 index 59ef193..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/14.txt +++ /dev/null @@ -1 +0,0 @@ -56 0.041007 0.094351 0.065533 0.077863 53.407448 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/140.txt b/services/our/src/tests/fixtures/prediction/labels/140.txt deleted file mode 100644 index 7a926ff..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/140.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.039132 0.079005 0.065348 0.073051 48.494751 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/141.txt b/services/our/src/tests/fixtures/prediction/labels/141.txt deleted file mode 100644 index 910fd58..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/141.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.039090 0.075240 0.065312 0.072294 47.814663 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/142.txt b/services/our/src/tests/fixtures/prediction/labels/142.txt deleted file mode 100644 index 9f25805..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/142.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.039028 0.076693 0.065173 0.072094 47.912033 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/143.txt b/services/our/src/tests/fixtures/prediction/labels/143.txt deleted file mode 100644 index 3432488..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/143.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.038899 0.073056 0.064984 0.071549 47.317184 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/144.txt b/services/our/src/tests/fixtures/prediction/labels/144.txt deleted file mode 100644 index 1c31a49..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/144.txt +++ /dev/null @@ -1 +0,0 @@ -47 0.038281 0.067039 0.063682 0.068646 45.645699 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/145.txt b/services/our/src/tests/fixtures/prediction/labels/145.txt deleted file mode 100644 index 949a350..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/145.txt +++ /dev/null @@ -1 +0,0 @@ -47 0.037488 0.066094 0.062121 0.068092 46.430637 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/146.txt b/services/our/src/tests/fixtures/prediction/labels/146.txt deleted file mode 100644 index e5aa4dc..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/146.txt +++ /dev/null @@ -1 +0,0 @@ -43 0.036806 0.065111 0.060806 0.064199 42.797428 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/147.txt b/services/our/src/tests/fixtures/prediction/labels/147.txt deleted file mode 100644 index 4903cfd..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/147.txt +++ /dev/null @@ -1 +0,0 @@ -43 0.036809 0.068780 0.060680 0.063662 42.322411 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/148.txt b/services/our/src/tests/fixtures/prediction/labels/148.txt deleted file mode 100644 index ac3a9f3..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/148.txt +++ /dev/null @@ -1 +0,0 @@ -41 0.036440 0.072136 0.059879 0.061923 40.799137 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/149.txt b/services/our/src/tests/fixtures/prediction/labels/149.txt deleted file mode 100644 index 7a14ba6..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/149.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.036187 0.067445 0.056100 0.063240 44.677353 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/15.txt b/services/our/src/tests/fixtures/prediction/labels/15.txt deleted file mode 100644 index ddeebd0..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/15.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.040299 0.095144 0.065489 0.078165 53.380753 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/16.txt b/services/our/src/tests/fixtures/prediction/labels/16.txt deleted file mode 100644 index fea4b94..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/16.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.040405 0.097322 0.066765 0.079255 53.374428 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/17.txt b/services/our/src/tests/fixtures/prediction/labels/17.txt deleted file mode 100644 index 2735d71..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/17.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.038764 0.090667 0.063157 0.076659 53.355133 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/18.txt b/services/our/src/tests/fixtures/prediction/labels/18.txt deleted file mode 100644 index 00b1802..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/18.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.038673 0.089891 0.063106 0.076448 53.004646 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/19.txt b/services/our/src/tests/fixtures/prediction/labels/19.txt deleted file mode 100644 index 1b5cf50..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/19.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.038899 0.091212 0.063614 0.076383 52.351440 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/2.txt b/services/our/src/tests/fixtures/prediction/labels/2.txt deleted file mode 100644 index 9a2b904..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/2.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.038586 0.088787 0.063747 0.075643 53.104782 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/20.txt b/services/our/src/tests/fixtures/prediction/labels/20.txt deleted file mode 100644 index 9a91d09..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/20.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.037872 0.087844 0.061520 0.075063 52.219879 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/21.txt b/services/our/src/tests/fixtures/prediction/labels/21.txt deleted file mode 100644 index 9d617e3..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/21.txt +++ /dev/null @@ -1 +0,0 @@ -50 0.037195 0.086863 0.060343 0.073201 50.691704 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/22.txt b/services/our/src/tests/fixtures/prediction/labels/22.txt deleted file mode 100644 index 20fb9a6..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/22.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.038759 0.092685 0.063432 0.076361 52.002579 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/23.txt b/services/our/src/tests/fixtures/prediction/labels/23.txt deleted file mode 100644 index cbebb54..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/23.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.040353 0.090205 0.065287 0.077373 51.746628 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/24.txt b/services/our/src/tests/fixtures/prediction/labels/24.txt deleted file mode 100644 index 0473012..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/24.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.040583 0.091694 0.066280 0.077802 51.581718 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/25.txt b/services/our/src/tests/fixtures/prediction/labels/25.txt deleted file mode 100644 index 6efe144..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/25.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.041297 0.094172 0.067527 0.076987 50.565460 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/26.txt b/services/our/src/tests/fixtures/prediction/labels/26.txt deleted file mode 100644 index 411ea8a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/26.txt +++ /dev/null @@ -1 +0,0 @@ -50 0.040312 0.090680 0.065473 0.075966 50.742157 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/27.txt b/services/our/src/tests/fixtures/prediction/labels/27.txt deleted file mode 100644 index 458492e..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/27.txt +++ /dev/null @@ -1 +0,0 @@ -50 0.039734 0.092913 0.064935 0.076198 50.960922 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/28.txt b/services/our/src/tests/fixtures/prediction/labels/28.txt deleted file mode 100644 index 8608d0b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/28.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.040137 0.089994 0.065064 0.074114 49.276997 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/29.txt b/services/our/src/tests/fixtures/prediction/labels/29.txt deleted file mode 100644 index 95eb993..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/29.txt +++ /dev/null @@ -1 +0,0 @@ -47 0.040732 0.094854 0.067243 0.076296 49.356400 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/3.txt b/services/our/src/tests/fixtures/prediction/labels/3.txt deleted file mode 100644 index 1bb0c4a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/3.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.038630 0.087661 0.063683 0.075626 52.907776 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/30.txt b/services/our/src/tests/fixtures/prediction/labels/30.txt deleted file mode 100644 index 0782515..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/30.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.041461 0.093046 0.068027 0.076524 49.280266 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/31.txt b/services/our/src/tests/fixtures/prediction/labels/31.txt deleted file mode 100644 index 7b30659..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/31.txt +++ /dev/null @@ -1 +0,0 @@ -46 0.040502 0.082802 0.064679 0.074476 48.285706 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/32.txt b/services/our/src/tests/fixtures/prediction/labels/32.txt deleted file mode 100644 index ea5376b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/32.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.040258 0.083422 0.064046 0.075326 49.381264 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/33.txt b/services/our/src/tests/fixtures/prediction/labels/33.txt deleted file mode 100644 index 61e917f..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/33.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.040601 0.090676 0.066223 0.076538 49.821045 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/34.txt b/services/our/src/tests/fixtures/prediction/labels/34.txt deleted file mode 100644 index 0123411..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/34.txt +++ /dev/null @@ -1 +0,0 @@ -46 0.039033 0.083210 0.063061 0.073626 48.440258 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/35.txt b/services/our/src/tests/fixtures/prediction/labels/35.txt deleted file mode 100644 index 4d3ddb1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/35.txt +++ /dev/null @@ -1 +0,0 @@ -43 0.032891 0.045700 0.029322 0.035714 35.217300 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/36.txt b/services/our/src/tests/fixtures/prediction/labels/36.txt deleted file mode 100644 index 2cb5cb0..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/36.txt +++ /dev/null @@ -1 +0,0 @@ -50 0.041740 0.059307 0.038156 0.048756 40.737473 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/37.txt b/services/our/src/tests/fixtures/prediction/labels/37.txt deleted file mode 100644 index d895592..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/37.txt +++ /dev/null @@ -1 +0,0 @@ -51 0.043773 0.062391 0.039251 0.053317 44.349907 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/38.txt b/services/our/src/tests/fixtures/prediction/labels/38.txt deleted file mode 100644 index 0aede67..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/38.txt +++ /dev/null @@ -1 +0,0 @@ -50 0.044851 0.059177 0.037444 0.047610 41.626480 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/39.txt b/services/our/src/tests/fixtures/prediction/labels/39.txt deleted file mode 100644 index 82fdf32..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/39.txt +++ /dev/null @@ -1 +0,0 @@ -49 0.043650 0.054320 0.035061 0.041959 39.615734 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/4.txt b/services/our/src/tests/fixtures/prediction/labels/4.txt deleted file mode 100644 index e64aaf5..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/4.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.039047 0.089085 0.064675 0.076483 53.375942 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/40.txt b/services/our/src/tests/fixtures/prediction/labels/40.txt deleted file mode 100644 index da8a00b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/40.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.047915 0.067200 0.042890 0.058544 45.186440 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/41.txt b/services/our/src/tests/fixtures/prediction/labels/41.txt deleted file mode 100644 index 7d1dba8..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/41.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.047528 0.066358 0.042432 0.058007 44.913727 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/42.txt b/services/our/src/tests/fixtures/prediction/labels/42.txt deleted file mode 100644 index eaa1cb1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/42.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.041072 0.056998 0.035125 0.052732 44.344086 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/43.txt b/services/our/src/tests/fixtures/prediction/labels/43.txt deleted file mode 100644 index cc1241e..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/43.txt +++ /dev/null @@ -1 +0,0 @@ -51 0.043158 0.061411 0.039824 0.057852 44.955292 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/44.txt b/services/our/src/tests/fixtures/prediction/labels/44.txt deleted file mode 100644 index 12f1502..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/44.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.039598 0.052803 0.031997 0.049200 40.695629 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/45.txt b/services/our/src/tests/fixtures/prediction/labels/45.txt deleted file mode 100644 index 83a8aad..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/45.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.038581 0.050030 0.030199 0.045505 40.698929 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/46.txt b/services/our/src/tests/fixtures/prediction/labels/46.txt deleted file mode 100644 index 6dfeb40..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/46.txt +++ /dev/null @@ -1 +0,0 @@ -41 0.036938 0.043018 0.028460 0.033426 32.071121 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/47.txt b/services/our/src/tests/fixtures/prediction/labels/47.txt deleted file mode 100644 index 9deee52..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/47.txt +++ /dev/null @@ -1 +0,0 @@ -40 0.036963 0.042987 0.028471 0.033255 31.860889 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/48.txt b/services/our/src/tests/fixtures/prediction/labels/48.txt deleted file mode 100644 index 864857a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/48.txt +++ /dev/null @@ -1 +0,0 @@ -36 0.042042 0.054596 0.038157 0.050414 32.152676 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/49.txt b/services/our/src/tests/fixtures/prediction/labels/49.txt deleted file mode 100644 index 8462647..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/49.txt +++ /dev/null @@ -1 +0,0 @@ -36 0.042830 0.055505 0.039300 0.051146 32.325150 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/5.txt b/services/our/src/tests/fixtures/prediction/labels/5.txt deleted file mode 100644 index 1499d38..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/5.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.039289 0.088586 0.064755 0.075773 52.296677 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/50.txt b/services/our/src/tests/fixtures/prediction/labels/50.txt deleted file mode 100644 index 1864c11..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/50.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.041617 0.047316 0.032837 0.037152 32.227730 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/51.txt b/services/our/src/tests/fixtures/prediction/labels/51.txt deleted file mode 100644 index 67dfaf5..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/51.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.041716 0.047384 0.032923 0.037170 32.099144 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/52.txt b/services/our/src/tests/fixtures/prediction/labels/52.txt deleted file mode 100644 index 9770109..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/52.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.036623 0.042752 0.029092 0.031746 31.368042 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/53.txt b/services/our/src/tests/fixtures/prediction/labels/53.txt deleted file mode 100644 index a0aea58..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/53.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.036620 0.042687 0.029048 0.031663 31.362764 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/54.txt b/services/our/src/tests/fixtures/prediction/labels/54.txt deleted file mode 100644 index d11e013..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/54.txt +++ /dev/null @@ -1 +0,0 @@ -41 0.038580 0.054718 0.037448 0.051601 35.002811 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/55.txt b/services/our/src/tests/fixtures/prediction/labels/55.txt deleted file mode 100644 index 7655d83..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/55.txt +++ /dev/null @@ -1 +0,0 @@ -41 0.037821 0.054225 0.036801 0.051092 34.945328 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/56.txt b/services/our/src/tests/fixtures/prediction/labels/56.txt deleted file mode 100644 index a7fb0ef..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/56.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.034458 0.054829 0.035582 0.055812 40.425453 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/57.txt b/services/our/src/tests/fixtures/prediction/labels/57.txt deleted file mode 100644 index 015255f..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/57.txt +++ /dev/null @@ -1 +0,0 @@ -48 0.034686 0.054091 0.035186 0.054277 40.062107 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/58.txt b/services/our/src/tests/fixtures/prediction/labels/58.txt deleted file mode 100644 index 14426b9..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/58.txt +++ /dev/null @@ -1 +0,0 @@ -57 0.038837 0.082894 0.062552 0.069445 51.872215 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/59.txt b/services/our/src/tests/fixtures/prediction/labels/59.txt deleted file mode 100644 index 685a8f1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/59.txt +++ /dev/null @@ -1 +0,0 @@ -32 0.022999 0.043750 0.022722 0.048968 31.945200 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/6.txt b/services/our/src/tests/fixtures/prediction/labels/6.txt deleted file mode 100644 index 7e83cb9..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/6.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.040092 0.091829 0.066258 0.077107 52.671627 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/60.txt b/services/our/src/tests/fixtures/prediction/labels/60.txt deleted file mode 100644 index f405358..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/60.txt +++ /dev/null @@ -1 +0,0 @@ -41 0.026247 0.049599 0.024864 0.050194 36.840691 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/61.txt b/services/our/src/tests/fixtures/prediction/labels/61.txt deleted file mode 100644 index 3baa9e3..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/61.txt +++ /dev/null @@ -1 +0,0 @@ -66 0.022907 0.039306 0.022662 0.046313 48.672504 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/62.txt b/services/our/src/tests/fixtures/prediction/labels/62.txt deleted file mode 100644 index 7d0d892..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/62.txt +++ /dev/null @@ -1 +0,0 @@ -57 0.039894 0.090226 0.061569 0.068168 51.285439 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/63.txt b/services/our/src/tests/fixtures/prediction/labels/63.txt deleted file mode 100644 index 9d3b156..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/63.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.048924 0.091334 0.059758 0.067995 50.548450 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/64.txt b/services/our/src/tests/fixtures/prediction/labels/64.txt deleted file mode 100644 index 3b71f65..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/64.txt +++ /dev/null @@ -1 +0,0 @@ -58 0.039831 0.087696 0.062446 0.068166 53.084751 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/65.txt b/services/our/src/tests/fixtures/prediction/labels/65.txt deleted file mode 100644 index db561b8..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/65.txt +++ /dev/null @@ -1 +0,0 @@ -58 0.040612 0.090068 0.065153 0.071738 54.392399 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/66.txt b/services/our/src/tests/fixtures/prediction/labels/66.txt deleted file mode 100644 index 2cb3e26..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/66.txt +++ /dev/null @@ -1 +0,0 @@ -60 0.041616 0.093175 0.065634 0.073091 55.869972 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/67.txt b/services/our/src/tests/fixtures/prediction/labels/67.txt deleted file mode 100644 index b418ac6..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/67.txt +++ /dev/null @@ -1 +0,0 @@ -56 0.040496 0.086040 0.062963 0.069799 53.591637 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/68.txt b/services/our/src/tests/fixtures/prediction/labels/68.txt deleted file mode 100644 index 2e7ee85..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/68.txt +++ /dev/null @@ -1 +0,0 @@ -59 0.041022 0.083298 0.064152 0.072956 55.851673 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/69.txt b/services/our/src/tests/fixtures/prediction/labels/69.txt deleted file mode 100644 index ce017be..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/69.txt +++ /dev/null @@ -1 +0,0 @@ -62 0.043478 0.091953 0.069978 0.079008 58.172695 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/7.txt b/services/our/src/tests/fixtures/prediction/labels/7.txt deleted file mode 100644 index 6016a81..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/7.txt +++ /dev/null @@ -1 +0,0 @@ -55 0.039878 0.092010 0.065897 0.077365 53.188076 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/70.txt b/services/our/src/tests/fixtures/prediction/labels/70.txt deleted file mode 100644 index 492af89..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/70.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.034369 0.058474 0.056676 0.065891 48.764679 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/71.txt b/services/our/src/tests/fixtures/prediction/labels/71.txt deleted file mode 100644 index d3200f5..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/71.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034419 0.063677 0.056727 0.065873 48.853603 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/72.txt b/services/our/src/tests/fixtures/prediction/labels/72.txt deleted file mode 100644 index cdbbd9a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/72.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.034378 0.063580 0.056653 0.065783 48.770065 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/73.txt b/services/our/src/tests/fixtures/prediction/labels/73.txt deleted file mode 100644 index 00696ad..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/73.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034456 0.063362 0.056788 0.065928 48.954887 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/74.txt b/services/our/src/tests/fixtures/prediction/labels/74.txt deleted file mode 100644 index ec57a03..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/74.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034375 0.059440 0.056584 0.065834 48.820354 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/75.txt b/services/our/src/tests/fixtures/prediction/labels/75.txt deleted file mode 100644 index ccea3bd..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/75.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034421 0.059616 0.056723 0.066008 48.958206 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/76.txt b/services/our/src/tests/fixtures/prediction/labels/76.txt deleted file mode 100644 index 4c9e2ed..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/76.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034434 0.059725 0.056748 0.066033 48.979515 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/77.txt b/services/our/src/tests/fixtures/prediction/labels/77.txt deleted file mode 100644 index f72eaf4..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/77.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034548 0.054414 0.057141 0.066319 49.319530 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/78.txt b/services/our/src/tests/fixtures/prediction/labels/78.txt deleted file mode 100644 index 8c5635e..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/78.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034338 0.052701 0.056745 0.066531 49.484806 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/79.txt b/services/our/src/tests/fixtures/prediction/labels/79.txt deleted file mode 100644 index 758062c..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/79.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034612 0.054135 0.057341 0.066714 49.643581 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/8.txt b/services/our/src/tests/fixtures/prediction/labels/8.txt deleted file mode 100644 index 4b37b3b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/8.txt +++ /dev/null @@ -1 +0,0 @@ -52 0.039667 0.088961 0.064458 0.075846 52.022839 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/80.txt b/services/our/src/tests/fixtures/prediction/labels/80.txt deleted file mode 100644 index 3ae0bef..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/80.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034607 0.054053 0.057334 0.066706 49.647636 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/81.txt b/services/our/src/tests/fixtures/prediction/labels/81.txt deleted file mode 100644 index 02a32d1..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/81.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034249 0.053221 0.056632 0.066137 49.059483 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/82.txt b/services/our/src/tests/fixtures/prediction/labels/82.txt deleted file mode 100644 index 9426df9..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/82.txt +++ /dev/null @@ -1 +0,0 @@ -54 0.034260 0.053261 0.056656 0.066161 49.091011 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/83.txt b/services/our/src/tests/fixtures/prediction/labels/83.txt deleted file mode 100644 index be803d0..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/83.txt +++ /dev/null @@ -1 +0,0 @@ -46 0.035543 0.078270 0.053312 0.060655 39.456207 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/84.txt b/services/our/src/tests/fixtures/prediction/labels/84.txt deleted file mode 100644 index a16151d..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/84.txt +++ /dev/null @@ -1 +0,0 @@ -47 0.035702 0.079416 0.054139 0.061860 40.916161 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/85.txt b/services/our/src/tests/fixtures/prediction/labels/85.txt deleted file mode 100644 index 802f54d..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/85.txt +++ /dev/null @@ -1 +0,0 @@ -44 0.035436 0.079698 0.053465 0.059294 37.065166 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/86.txt b/services/our/src/tests/fixtures/prediction/labels/86.txt deleted file mode 100644 index 3cb891b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/86.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.034088 0.075423 0.050748 0.055254 32.651058 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/87.txt b/services/our/src/tests/fixtures/prediction/labels/87.txt deleted file mode 100644 index ecabf64..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/87.txt +++ /dev/null @@ -1 +0,0 @@ -39 0.032986 0.070509 0.048970 0.054720 32.961876 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/88.txt b/services/our/src/tests/fixtures/prediction/labels/88.txt deleted file mode 100644 index 2c81227..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/88.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.032306 0.068780 0.047561 0.052743 30.510756 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/89.txt b/services/our/src/tests/fixtures/prediction/labels/89.txt deleted file mode 100644 index 92fcf70..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/89.txt +++ /dev/null @@ -1 +0,0 @@ -33 0.031765 0.067288 0.046688 0.050976 29.676157 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/9.txt b/services/our/src/tests/fixtures/prediction/labels/9.txt deleted file mode 100644 index 63a0b1c..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/9.txt +++ /dev/null @@ -1 +0,0 @@ -53 0.039416 0.087546 0.062930 0.075004 51.850227 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/90.txt b/services/our/src/tests/fixtures/prediction/labels/90.txt deleted file mode 100644 index dadb00a..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/90.txt +++ /dev/null @@ -1 +0,0 @@ -32 0.032639 0.069295 0.046686 0.049750 28.727793 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/91.txt b/services/our/src/tests/fixtures/prediction/labels/91.txt deleted file mode 100644 index 4a1e1b3..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/91.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.032972 0.061634 0.045092 0.051609 29.038794 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/92.txt b/services/our/src/tests/fixtures/prediction/labels/92.txt deleted file mode 100644 index 956e47b..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/92.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.034734 0.065177 0.044635 0.050590 28.128407 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/93.txt b/services/our/src/tests/fixtures/prediction/labels/93.txt deleted file mode 100644 index 92df475..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/93.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.032320 0.056962 0.042639 0.047532 27.319426 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/94.txt b/services/our/src/tests/fixtures/prediction/labels/94.txt deleted file mode 100644 index 9ac2a36..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/94.txt +++ /dev/null @@ -1 +0,0 @@ -36 0.031656 0.055654 0.040966 0.049437 28.343576 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/95.txt b/services/our/src/tests/fixtures/prediction/labels/95.txt deleted file mode 100644 index 4546e86..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/95.txt +++ /dev/null @@ -1 +0,0 @@ -34 0.031890 0.055906 0.042168 0.049285 28.531000 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/96.txt b/services/our/src/tests/fixtures/prediction/labels/96.txt deleted file mode 100644 index 1d3e469..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/96.txt +++ /dev/null @@ -1 +0,0 @@ -32 0.034397 0.063852 0.044452 0.051638 29.653748 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/97.txt b/services/our/src/tests/fixtures/prediction/labels/97.txt deleted file mode 100644 index b57ac97..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/97.txt +++ /dev/null @@ -1 +0,0 @@ -32 0.035273 0.066313 0.045359 0.051649 29.548565 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/98.txt b/services/our/src/tests/fixtures/prediction/labels/98.txt deleted file mode 100644 index fed89b6..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/98.txt +++ /dev/null @@ -1 +0,0 @@ -36 0.035006 0.063150 0.044154 0.051334 30.672239 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/labels/99.txt b/services/our/src/tests/fixtures/prediction/labels/99.txt deleted file mode 100644 index 1619706..0000000 --- a/services/our/src/tests/fixtures/prediction/labels/99.txt +++ /dev/null @@ -1 +0,0 @@ -61 0.035569 0.067777 0.045799 0.061890 44.171967 \ No newline at end of file diff --git a/services/our/src/tests/fixtures/prediction/output-sharp.png b/services/our/src/tests/fixtures/prediction/output-sharp.png new file mode 100644 index 0000000..e27c90d Binary files /dev/null and b/services/our/src/tests/fixtures/prediction/output-sharp.png differ diff --git a/services/our/src/tests/funscripts.integration.test.ts b/services/our/src/tests/funscripts.integration.test.ts index 37ca9cd..7fd6d07 100644 --- a/services/our/src/tests/funscripts.integration.test.ts +++ b/services/our/src/tests/funscripts.integration.test.ts @@ -1,5 +1,5 @@ // funscripts.integration.ts -import { describe, it, expect, vi, beforeEach, afterEach, beforeAll } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { buildFunscript, } from '../utils/funscripts'; @@ -8,14 +8,9 @@ import { join } from 'node:path'; import { tmpdir } from 'node:os'; -// Integration test (no mocks) describe('[integration] buildFunscript', () => { const TMP_DIR = join(tmpdir(), 'funscript-test'); - beforeAll(() => { - vi.doUnmock('fs-extra'); - }); - beforeEach(async () => { await mkdir(TMP_DIR, { recursive: true }); }); diff --git a/services/our/src/tests/funscripts.unit.test.ts b/services/our/src/tests/funscripts.unit.test.ts index 8901e82..a9bbd32 100644 --- a/services/our/src/tests/funscripts.unit.test.ts +++ b/services/our/src/tests/funscripts.unit.test.ts @@ -1,7 +1,7 @@ // funscripts.unit.ts import { describe, it, expect, vi, beforeEach, afterEach, beforeAll } from 'vitest'; import { - loadClassPositionMap, + classPositionMap, generatePatternPositions, generateActions, writeFunscript, @@ -31,19 +31,6 @@ const mockedWriteJson = vi.mocked(writeJson); describe('funscript utils', () => { - describe('loadClassPositionMap', () => { - it('maps known and unknown class names correctly', async () => { - const data: DataYaml = { - names: { '0': 'RespondingTo', '1': 'UnknownClass' }, - path: '', - train: '', - val: '' - }; - const result = await loadClassPositionMap(data); - expect(result.RespondingTo).toBe(5); - expect(result.UnknownClass).toBe(0); - }); - }); describe('generatePatternPositions', () => { it('generates wave pattern correctly', () => { diff --git a/services/our/src/tests/inference.integration.test.ts.noexec b/services/our/src/tests/inference.integration.test.ts.noexec new file mode 100644 index 0000000..46b705e --- /dev/null +++ b/services/our/src/tests/inference.integration.test.ts.noexec @@ -0,0 +1,214 @@ +// inference.integration.test.ts + +// this idea was to use onnx, so we could run inference via node. +// I couldn't figure it out-- the detection bounding boxes were in the wrong place. +// I'm going back to shelling out to pytorch. saving this for reference. + +import { describe, it, expect, vi, beforeEach, afterEach, beforeAll } from 'vitest'; +import { InferenceSession, Tensor } from 'onnxruntime-node'; +import { join } from 'node:path'; +import { preprocessImage } from '../utils/vibeui'; +import { createCanvas, loadImage } from 'canvas'; +import { writeFileSync } from 'fs'; +import sharp from 'sharp'; + +const __dirname = import.meta.dirname; + +const distDir = join(__dirname, '../../dist') +const fixturesDir = join(__dirname, '..', 'tests', 'fixtures') +const modelPath = join(distDir, 'vibeui', 'vibeui.onnx') +const sampleFrame = join(fixturesDir, 'prediction', 'frames', '000001.jpg') + +const NUM_BOXES = 8400; +const NUM_CLASSES = 19; +const CONFIDENCE_THRESHOLD = 0.9; // tune as needed +const IMAGE_WIDTH = 640; +const IMAGE_HEIGHT = 640; + +type Detection = { + x1: number; + y1: number; + x2: number; + y2: number; + confidence: number; + classIndex: number; + classScore: number; +}; + +function iou(a: Detection, b: Detection): number { + const x1 = Math.max(a.x1, b.x1); + const y1 = Math.max(a.y1, b.y1); + const x2 = Math.min(a.x2, b.x2); + const y2 = Math.min(a.y2, b.y2); + + const intersection = Math.max(0, x2 - x1) * Math.max(0, y2 - y1); + const areaA = (a.x2 - a.x1) * (a.y2 - a.y1); + const areaB = (b.x2 - b.x1) * (b.y2 - b.y1); + const union = areaA + areaB - intersection; + + return intersection / union; +} + +function nms(detections: Detection[], iouThreshold = 0.45, topK = 50): Detection[] { + const sorted = [...detections].sort((a, b) => b.confidence - a.confidence); + const selected: Detection[] = []; + + while (sorted.length > 0 && selected.length < topK) { + const best = sorted.shift()!; + selected.push(best); + + for (let i = sorted.length - 1; i >= 0; i--) { + if (iou(best, sorted[i]) > iouThreshold) { + sorted.splice(i, 1); // remove overlapping box + } + } + } + + return selected; +} + +function softmax(logits: Float32Array): number[] { + const max = Math.max(...logits); + const exps = logits.map(x => Math.exp(x - max)); + const sum = exps.reduce((a, b) => a + b, 0); + return exps.map(e => e / sum); +} + +function sigmoid(x: number): number { + return 1 / (1 + Math.exp(-x)); +} + +function postprocessTensor(tensor: Tensor): Detection[] { + const results: Detection[] = []; + const data = tensor.cpuData; + + for (let i = 0; i < NUM_BOXES; i++) { + const offset = i * 24; + + const cx = data[offset + 0]; // already in pixel coords + const cy = data[offset + 1]; + const w = data[offset + 2]; + const h = data[offset + 3]; + + const objectness = sigmoid(data[offset + 4]); + if (objectness < CONFIDENCE_THRESHOLD) continue; + + const classLogits = data.slice(offset + 5, offset + 24); + const classScores = softmax(classLogits as Float32Array); + + const maxClassScore = Math.max(...classScores); + const classIndex = classScores.findIndex(score => score === maxClassScore); + + const confidence = objectness * maxClassScore; + if (confidence < CONFIDENCE_THRESHOLD) continue; + + const x1 = cx - w / 2; + const y1 = cy - h / 2; + const x2 = cx + w / 2; + const y2 = cy + h / 2; + + results.push({ + x1, + y1, + x2, + y2, + confidence, + classIndex, + classScore: maxClassScore, + }); + } + + return results; +} + + +async function renderDetectionsSharp( + imagePath: string, + detections: Detection[], + outputPath: string, + classNames?: string[] +) { + const baseImage = sharp(imagePath); + const { width, height } = await baseImage.metadata(); + + if (!width || !height) throw new Error('Image must have width and height'); + + const svg = createSvgOverlay(width, height, detections, classNames); + const overlay = Buffer.from(svg); + + await baseImage + .composite([{ input: overlay, blend: 'over' }]) + .toFile(outputPath); +} + +function createSvgOverlay( + width: number, + height: number, + detections: Detection[], + classNames?: string[] +): string { + const elements = detections.map(det => { + const x = det.x1; + const y = det.y1; + const w = det.x2 - det.x1; + const h = det.y2 - det.y1; + const className = classNames?.[det.classIndex] ?? `cls ${det.classIndex}`; + const confPct = (det.confidence * 100).toFixed(1); + + return ` + + + ${className} (${confPct}%) + + `; + }); + + return ` + + ${elements.join('\n')} + + `; +} + + + +describe('inference', () => { + it('pytorch', async () => { + const session = await InferenceSession.create(modelPath) + const imageTensor = await preprocessImage(sampleFrame); + console.log(session.inputNames) + console.log(session.outputNames) + const feeds = { + images: imageTensor + } + + const res = await session.run(feeds) + + const { output0 } = res + + const detections = postprocessTensor(output0); + // console.log(detections) + // console.log(detections.length) + // console.log(detections.slice(0, 5)); // first 5 predictions + + const finalDetections = nms(detections, undefined, 3); + console.log(finalDetections); + console.log(`there were ${finalDetections.length} detections`) + + const classNames = Array.from({ length: 19 }, (_, i) => `class${i}`); + await renderDetectionsSharp( + sampleFrame, + finalDetections, + join(fixturesDir, 'prediction', 'output-sharp.png'), + classNames + ); + + + expect(output0.dims).toEqual([1, 24, 8400]); + expect(output0.type).toBe('float32'); + expect(output0.cpuData[0]).toBeGreaterThan(0); // or some expected value + + }) +}) \ No newline at end of file diff --git a/services/our/src/tests/runInferenceOnFrame.unit.test.ts b/services/our/src/tests/runInferenceOnFrame.unit.test.ts new file mode 100644 index 0000000..d961261 --- /dev/null +++ b/services/our/src/tests/runInferenceOnFrame.unit.test.ts @@ -0,0 +1,107 @@ +// import { describe, it, expect, vi } from 'vitest'; +// import { runInferenceOnFrame } from '../utils/vibeui'; +// import { +// type InferenceSession, +// type Tensor, +// } from 'onnxruntime-node' + +// type DetectionOutput = { +// bbox: [number, number, number, number]; +// confidence: number; +// classIndex: number; +// }; + +// describe('runInferenceOnFrame', () => { +// it('parses detections and filters by confidence, rounds classIndex, includes out-of-range classes', async () => { +// // Mock session +// const mockSession = { +// inputNames: ['input'], +// outputNames: ['output'], +// run: vi.fn().mockResolvedValue({ +// output: { +// data: new Float32Array([ +// 0.1, 0.2, 0.3, 0.4, 0.5, 10, // valid detection +// 0.2, 0.3, 0.4, 0.5, 0.2, 5, // confidence too low, filtered out +// 0.3, 0.4, 0.5, 0.6, 0.9, 54 // class 54 out of range, but included +// ]), +// dims: [3, 6] +// } +// }), +// } as unknown as InferenceSession; + +// // Mock tensor input, content irrelevant here +// const mockTensor = {} as Tensor; + +// const detections = await runInferenceOnFrame(mockSession, mockTensor); + +// expect(detections).toHaveLength(2); +// expect(detections[0]).toEqual({ +// bbox: [0.1, 0.2, 0.3, 0.4], +// confidence: 0.5, +// classIndex: 10, +// }); +// expect(detections[1]).toEqual({ +// bbox: [0.3, 0.4, 0.5, 0.6], +// confidence: 0.9, +// classIndex: 54, +// }); +// }); + +// it('throws if output missing or data is wrong type', async () => { +// const badSession = { +// inputNames: ['input'], +// outputNames: ['output'], +// run: vi.fn().mockResolvedValue({ +// output: { +// data: [1, 2, 3], // not Float32Array +// dims: [1, 6] +// } +// }), +// } as unknown as InferenceSession; + +// await expect(runInferenceOnFrame(badSession, {} as Tensor)).rejects.toThrow( +// 'Unexpected model output format' +// ); +// }); +// }); + + + +import { describe, it, expect } from 'vitest'; +import fs from 'fs/promises'; +import path, { resolve } from 'path'; +import ort from 'onnxruntime-node'; +import sharp from 'sharp'; +import { preprocessImage, runModelInference } from '../utils/vibeui'; + + +const __dirname = import.meta.dirname; +const FIXTURE_DIR = resolve(__dirname, 'fixtures'); +const DIST_DIR = resolve(__dirname, '..', '..', 'dist'); +const VIBEUI_DIR = resolve(DIST_DIR, 'vibeui'); +const VIDEO = resolve(FIXTURE_DIR, 'sample.mp4'); +const MODEL_PATH = resolve(VIBEUI_DIR, 'vibeui.onnx'); +const IMAGE_PATH = resolve(FIXTURE_DIR, 'prediction/frames/000001.jpg'); + + +describe.skip('runInferenceOnFrame integration', () => { + it('runs inference on real image and returns valid detections', async () => { + // Load ONNX model session + const session = await ort.InferenceSession.create(MODEL_PATH); + + // Prepare input tensor from JPG image + const inputTensor = await preprocessImage(IMAGE_PATH); + + // Run inference + const detections = await runModelInference(session, inputTensor); + + // Check output is not empty and class indices are within range + expect(detections.length).toBeGreaterThan(0); + for (const det of detections) { + expect(det.confidence).toBeGreaterThan(0.3); + expect(det.classIndex).toBeGreaterThanOrEqual(0); + expect(det.classIndex).toBeLessThan(19); // since you have 19 classes + expect(det.bbox).toHaveLength(4); + } + }); +}); diff --git a/services/our/src/tests/vibeui.integration.test.ts b/services/our/src/tests/vibeui.integration.test.ts new file mode 100644 index 0000000..304e287 --- /dev/null +++ b/services/our/src/tests/vibeui.integration.test.ts @@ -0,0 +1,65 @@ +import { describe, it, expect, beforeAll, afterAll, beforeEach, vi, type Mock } from 'vitest'; +import { vibeuiInference, processLabelFiles, getModelClasses } from '../utils/vibeui'; +import { resolve, join } from 'node:path'; +import { readdir, readFile, rm } from 'node:fs/promises'; +import { readJson } from 'fs-extra'; +import { DataYaml } from '../utils/funscripts'; + + +const __dirname = import.meta.dirname; +const FIXTURE_DIR = resolve(__dirname, 'fixtures'); +const DIST_DIR = resolve(__dirname, '..', '..', 'dist'); +const VIBEUI_DIR = resolve(DIST_DIR, 'vibeui'); +const VIDEO = resolve(FIXTURE_DIR, 'sample.mp4'); +const MODEL = resolve(VIBEUI_DIR, 'vibeui.onnx'); + + + +describe('[integration] vibeuiInference', () => { + let outputPath: string; + + beforeAll(async () => { + outputPath = await vibeuiInference(MODEL, VIDEO); + console.log(`outputPath=${outputPath}`) + }, 35_000); + + afterAll(async () => { + // await rm(outputPath, { recursive: true, force: true }); + console.log('@todo cleanup') + }); + + it('outputs detection labels and frames', async () => { + const frames = await readdir(join(outputPath, 'frames')); + const labels = await readdir(join(outputPath, 'labels')); + expect(frames.length).toBeGreaterThan(0); + expect(labels.length).toBeGreaterThan(0); + }); + + it('writes properly formatted label files', async () => { + const labelFile = join(outputPath, 'labels', '1.txt'); + const content = await readFile(labelFile, 'utf8'); + + const firstLine = content.split('\n')[0].trim().replace(/\r/g, ''); + console.log('First line content:', JSON.stringify(firstLine)); + + // Expect initial class number + exactly 5 floats/ints after it (6 total numbers) + expect(firstLine).toMatch(/^\d+( (-?\d+(\.\d+)?)){5}$/); + }); + + it('contains only 1-10 lines', async () => { + const labelFile = join(outputPath, 'labels', '1.txt'); + const content = await readFile(labelFile, 'utf8'); + + const lines = content + .split('\n') + .map(line => line.trim()) + .filter(line => line.length > 0); // ignore empty lines + + expect(lines.length).toBeGreaterThanOrEqual(1); + expect(lines.length).toBeLessThanOrEqual(10); + }); + + + + +}); diff --git a/services/our/src/tests/vibeui.spec.ts b/services/our/src/tests/vibeui.spec.ts deleted file mode 100644 index a0c4670..0000000 --- a/services/our/src/tests/vibeui.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { describe, it, expect, beforeAll, afterAll, beforeEach, vi, type Mock } from 'vitest'; -import { vibeuiInference, processLabelFiles } from '../utils/vibeui'; -import { resolve, join } from 'node:path'; -import { readdir, readFile, rm } from 'node:fs/promises'; -import { DataYaml } from '../utils/funscripts'; - -const __dirname = import.meta.dirname; -const FIXTURE_DIR = resolve(__dirname, 'fixtures'); -const DIST_DIR = resolve(__dirname, '..', '..', 'dist'); -const VIBEUI_DIR = resolve(DIST_DIR, 'vibeui'); -const VIDEO = resolve(FIXTURE_DIR, 'sample.mp4'); -const MODEL = resolve(VIBEUI_DIR, 'vibeui.onnx'); -const YAML = resolve(VIBEUI_DIR, 'data.yaml'); - -describe('[unit] processLabelFiles', () => { - const mockLabelDir = '/mock/labels'; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('processes label files and returns merged detection segments', async () => { - // Mock data.names with string keys for class indexes - const data: DataYaml = { - names: { - '0': 'person', - '1': 'car', - }, - path: '', - train: '', - val: '', - }; - - // Mock file list in directory - (readdir as Mock).mockResolvedValue([ - '0.txt', - '1.txt', - 'invalid.txt', - 'notalabel.jpg', - '2.txt', - ]); - - // Mock content for each label file - (readFile as Mock).mockImplementation(async (filePath: string) => { - const file = filePath.split('/').pop(); - switch (file) { - case '0.txt': - // Two detections, only one with confidence >= 0.7 - return '0 0.1 0.2 0.3 0.4 0.6\n1 0.5 0.5 0.5 0.5 0.8'; - case '1.txt': - // One detection below threshold - return '0 0.1 0.2 0.3 0.4 0.5'; - case '2.txt': - // Multiple lines, highest confidence 0.9 for class 0 - return '0 0.1 0.2 0.3 0.4 0.9\n1 0.2 0.3 0.4 0.5 0.85'; - default: - return ''; - } - }); - - const results = await processLabelFiles(mockLabelDir, data); - - // Expected: - // - frame 0: class 1 (car), confidence 0.8 - // - frame 1: no detection >= 0.7 - // - frame 2: class 0 (person), confidence 0.9 (higher than class 1's 0.85) - // Merge segments by className: - // Since frame 0 detection is 'car', frame 2 detection is 'person', segments should not merge. - expect(results).toEqual([ - { startFrame: 0, endFrame: 0, className: 'car' }, - { startFrame: 2, endFrame: 2, className: 'person' }, - ]); - }); - - it('skips files with invalid filenames or frame indices', async () => { - (readdir as Mock).mockResolvedValue(['abc.txt', '123.txt']); - (readFile as Mock).mockResolvedValue('0 0.1 0.2 0.3 0.4 0.75'); - - const data = { names: { '0': 'person' }, val: '', train: '', path: '' }; - const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { }); - - const results = await processLabelFiles(mockLabelDir, data); - - expect(consoleSpy).toHaveBeenCalledWith('Skipping invalid filename: abc.txt'); - expect(results).toEqual([ - { startFrame: 123, endFrame: 123, className: 'person' }, - ]); - - consoleSpy.mockRestore(); - }); -}); - -describe('[integration] vibeuiInference', () => { - let outputPath: string; - - - beforeAll(async () => { - outputPath = await vibeuiInference(MODEL, VIDEO); - }, 35_000); - - afterAll(async () => { - await rm(outputPath, { recursive: true, force: true }); - }); - - it('outputs detection labels and frames', async () => { - const frames = await readdir(join(outputPath, 'frames')); - const labels = await readdir(join(outputPath, 'labels')); - expect(frames.length).toBeGreaterThan(0); - expect(labels.length).toBeGreaterThan(0); - }); - - it('writes properly formatted label files', async () => { - const labelFile = join(outputPath, 'labels', '1.txt'); - const content = await readFile(labelFile, 'utf8'); - - const firstLine = content.split('\n')[0].trim().replace(/\r/g, ''); - console.log('First line content:', JSON.stringify(firstLine)); - - // Expect initial class number + exactly 5 floats/ints after it (6 total numbers) - expect(firstLine).toMatch(/^\d+( (-?\d+(\.\d+)?)){5}$/); - }); - - - -}); diff --git a/services/our/src/utils/funscripts.ts b/services/our/src/utils/funscripts.ts index b8532e4..1abbd49 100644 --- a/services/our/src/utils/funscripts.ts +++ b/services/our/src/utils/funscripts.ts @@ -32,62 +32,30 @@ export interface ClassPositionMap { } -export async function loadClassPositionMap(data: DataYaml): Promise { - try { - if ( - !data || - typeof data !== 'object' || - !('names' in data) || - typeof data.names !== 'object' || - data.names === null || - Object.keys(data.names).length === 0 - ) { - throw new Error('Invalid data.yaml: "names" field is missing, not an object, or empty'); - } +export const classPositionMap: ClassPositionMap = { + RespondingTo: 5, + ControlledByTipper: 50, + ControlledByTipperHigh: 80, + ControlledByTipperLow: 20, + ControlledByTipperMedium: 50, + ControlledByTipperUltrahigh: 100, + Ring1: 30, + Ring2: 40, + Ring3: 50, + Ring4: 60, + Earthquake: 'pattern', + Fireworks: 'pattern', + Pulse: 'pattern', + Wave: 'pattern', + Pause: 0, + RandomTime: 70, + HighLevel: 80, + LowLevel: 20, + MediumLevel: 50, + UltraHighLevel: 95 +}; - const positionMap: ClassPositionMap = { - RespondingTo: 5, - ControlledByTipper: 50, - ControlledByTipperHigh: 80, - ControlledByTipperLow: 20, - ControlledByTipperMedium: 50, - ControlledByTipperUltrahigh: 100, - Ring1: 30, - Ring2: 40, - Ring3: 50, - Ring4: 60, - Earthquake: 'pattern', - Fireworks: 'pattern', - Pulse: 'pattern', - Wave: 'pattern', - Pause: 0, - RandomTime: 70, - HighLevel: 80, - LowLevel: 20, - MediumLevel: 50, - UltraHighLevel: 95 - }; - - const names = Object.values(data.names); - for (const name of names) { - if (typeof name !== 'string' || name.trim() === '') { - console.log(`Skipping invalid class name: ${name}`); - continue; - } - if (!(name in positionMap)) { - console.log(`No position mapping for class "${name}", defaulting to 0`); - positionMap[name] = 0; - } - } - - console.log(`Loaded class position map: ${JSON.stringify(positionMap)}`); - return positionMap; - } catch (error) { - console.error(`Error loading data.yaml: ${error instanceof Error ? error.message : 'Unknown error'}`); - throw error; - } -} export function generatePatternPositions(startMs: number, durationMs: number, className: string, fps: number): FunscriptAction[] { const actions: FunscriptAction[] = []; @@ -121,9 +89,21 @@ export function generatePatternPositions(startMs: number, durationMs: number, cl return actions; } - - -export function generateActions(totalDurationMs: number, fps: number, detectionSegments: Detection[], classPositionMap: ClassPositionMap): FunscriptAction[] { +/** + * Generates Funscript actions based on detection segments and a class-to-position mapping. + * + * - Creates static position actions at regular intervals (default 100ms). + * - Maps each timestamp to a position if a detection segment is active at that frame. + * - If a class is mapped to `"pattern"` in `classPositionMap`, generates additional patterned actions for that segment. + * - Merges and deduplicates actions by timestamp. + * + * @param totalDurationMs - Total video duration in milliseconds. + * @param fps - Frames per second of the video. + * @param detectionSegments - Array of detection segments with frame ranges and class names. + * @param classPositionMap - Maps class names to either a static position (0–100) or the string `"pattern"` to trigger pattern generation. + * @returns An array of unique, time-sorted `FunscriptAction` objects. + */ +export function generateActions1(totalDurationMs: number, fps: number, detectionSegments: Detection[], classPositionMap: ClassPositionMap): FunscriptAction[] { const intervalMs = 100; const actions: FunscriptAction[] = []; @@ -169,6 +149,92 @@ export function generateActions(totalDurationMs: number, fps: number, detectionS return uniqueActions; } +export function generateActions2( + totalDurationMs: number, + fps: number, + detectionSegments: Detection[], + classPositionMap: ClassPositionMap +): FunscriptAction[] { + const intervalMs = 100; + const actions: FunscriptAction[] = []; + + + + console.debug('[generateActions] Total duration (ms):', totalDurationMs); + console.debug('[generateActions] FPS:', fps); + console.debug('[generateActions] Detection segments:', detectionSegments); + console.debug('[generateActions] Class position map:', classPositionMap); + + // Generate static position actions + for (let timeMs = 0; timeMs <= totalDurationMs; timeMs += intervalMs) { + const frameIndex = Math.floor((timeMs / 1000) * fps); + let position = 0; + let matchedSegment: Detection | undefined; + + for (const segment of detectionSegments) { + if (frameIndex >= segment.startFrame && frameIndex <= segment.endFrame) { + const className = segment.className; + matchedSegment = segment; + + if (typeof classPositionMap[className] === 'number') { + position = classPositionMap[className]; + break; + } else { + console.warn(`[generateActions] Static class not mapped to number: ${className}`); + } + } + } + + if (!matchedSegment) { + console.debug(`[generateActions] No matching segment for time ${timeMs} (frame ${frameIndex})`); + } + + actions.push({ at: timeMs, pos: position }); + } + + // Overlay pattern-based actions + for (const segment of detectionSegments) { + const className = segment.className; + + if (classPositionMap[className] === 'pattern') { + const startMs = Math.floor((segment.startFrame / fps) * 1000); + const durationMs = Math.floor(((segment.endFrame - segment.startFrame + 1) / fps) * 1000); + + console.debug(`[generateActions] Generating pattern for class "${className}" from ${startMs}ms for ${durationMs}ms`); + const patternActions = generatePatternPositions(startMs, durationMs, className, fps); + + console.debug(`[generateActions] Generated ${patternActions.length} pattern actions for class "${className}"`); + actions.push(...patternActions); + } + } + + // Sort actions by time and remove duplicates + actions.sort((a, b) => a.at - b.at); + const uniqueActions: FunscriptAction[] = []; + let lastTime = -1; + for (const action of actions) { + if (action.at !== lastTime) { + uniqueActions.push(action); + lastTime = action.at; + } + } + + console.debug(`[generateActions] Final action count: ${uniqueActions.length}`); + + return uniqueActions; +} + +/** + * Writes a Funscript file to disk in JSON format. + * + * - Wraps the provided actions in a Funscript object with version `1.0`. + * - Saves the JSON to the specified output path. + * - Logs the file path and action count to the console. + * + * @param outputPath - Destination file path for the .funscript output. + * @param actions - Array of `FunscriptAction` entries to include. + * @throws If writing to the file system fails. + */ export async function writeFunscript(outputPath: string, actions: FunscriptAction[]) { const funscript: Funscript = { version: '1.0', actions }; @@ -179,26 +245,36 @@ export async function writeFunscript(outputPath: string, actions: FunscriptActio +/** + * Builds a Funscript file from YOLO prediction output and video metadata. + * + * - Loads the model's class definitions and video FPS/frame count. + * - Parses label files and maps detections to time-based actions. + * - Generates a Funscript JSON object and writes it to disk. + * + * @param predictionOutput - Path to the YOLO prediction output directory. + * @param videoPath - Path to the source video file. + * @returns Path to the generated Funscript file (.funscript). + * @throws If there is an error processing labels or writing the Funscript. + */ export async function buildFunscript( - dataYamlPath: string, predictionOutput: string, videoPath: string ): Promise { const labelDir = join(predictionOutput, 'labels'); const outputPath = join(process.env.CACHE_ROOT ?? '/tmp', `${nanoid()}.funscript`); - console.log(`Starting Funscript generation. outputPath=${outputPath}`); try { - const data = await loadDataYaml(dataYamlPath) - const classPositionMap = await loadClassPositionMap(data); + const data = await loadDataYaml(join(env.VIBEUI_DIR, 'data.yaml')) const { fps, totalFrames } = await loadVideoMetadata(videoPath); const detectionSegments = await processLabelFiles(labelDir, data); const totalDurationMs = Math.floor((totalFrames / fps) * 1000); - const actions = generateActions(totalDurationMs, fps, detectionSegments, classPositionMap); - await writeFunscript(outputPath, actions); - return outputPath; + const actions = generateActions1(totalDurationMs, fps, detectionSegments, classPositionMap); + await writeFunscript(outputPath, actions); + + return outputPath; } catch (error) { console.error(`Error generating Funscript: ${error instanceof Error ? error.message : 'Unknown error'}`); throw error; diff --git a/services/our/src/utils/python.ts b/services/our/src/utils/python.ts new file mode 100644 index 0000000..ba6144a --- /dev/null +++ b/services/our/src/utils/python.ts @@ -0,0 +1,70 @@ +import { getNanoSpawn } from "./nanoSpawn"; +import { join } from "node:path"; +import { env } from "../config/env"; +import which from "which"; +import { existsSync } from "fs-extra"; + +export async function preparePython() { + const spawn = await getNanoSpawn(); + const venvPath = env.VENV; + + // Determine Python executable + let pythonCmd; + try { + pythonCmd = which.sync("python3"); + } catch { + console.error("Python is not installed or not in PATH."); + throw new Error("Python not found in PATH."); + } + + // If venv doesn't exist, create it + if (!existsSync(venvPath)) { + console.error("Python venv not found. Creating one..."); + + try { + await spawn(pythonCmd, ["-m", "venv", venvPath], { + cwd: env.APP_DIR, + }); + + console.log("Python venv successfully created."); + } catch (err) { + console.error("Failed to create Python venv:", err); + throw new Error( + "Python venv creation failed. Check if python3 and python3-venv are installed." + ); + } + } else { + console.log("Using existing Python venv."); + } + + // Activate pip in the venv + const pipCmd = join(venvPath, "bin", "pip"); + + // Check if YOLO exists (example: checking if 'yolo' package is installed) + // This check can be customized to your specific condition (e.g., check a file or run `pip show yolo`) + let yoloExists = false; + try { + // Run `pip show yolov5` or your yolo package name to check if installed + await spawn(pipCmd, ["show", "yolov5"], { cwd: env.APP_DIR }); + yoloExists = true; + } catch { + yoloExists = false; + } + + if (!yoloExists) { + console.log("YOLO not found in venv. Installing requirements.txt..."); + + try { + // Install requirements.txt using pip inside venv + await spawn(pipCmd, ["install", "-r", "requirements.txt"], { + cwd: env.APP_DIR, + }); + console.log("✅ requirements.txt installed successfully."); + } catch (err) { + console.error("Failed to install requirements.txt:", err); + throw new Error("requirements.txt installation failed."); + } + } else { + console.log("YOLO detected in venv, skipping requirements installation."); + } +} diff --git a/services/our/src/utils/vibeui.ts b/services/our/src/utils/vibeui.ts index 11f223d..a75b2d2 100644 --- a/services/our/src/utils/vibeui.ts +++ b/services/our/src/utils/vibeui.ts @@ -8,6 +8,9 @@ import { getNanoSpawn } from "./nanoSpawn"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import which from "which"; import { env } from '../config/env'; +import fs from 'fs/promises'; +import { readJson } from 'fs-extra'; +import { preparePython } from './python'; interface Detection { startFrame: number; @@ -72,54 +75,9 @@ export async function preprocessImage(imagePath: string): Promise { return new ort.Tensor('float32', floatArray, [1, 3, inputHeight, inputWidth]); } -export async function runInferenceOnFrame(session: ort.InferenceSession, tensor: ort.Tensor): Promise { - // The input name depends on your ONNX model, often 'images' or similar. - const feeds: Record = {}; - const inputName = session.inputNames[0]; - feeds[inputName] = tensor; - const results = await session.run(feeds); - // You need to parse outputs according to your ONNX model - // Example: - // Let's say outputNames: ['boxes', 'scores', 'labels'] - // This depends on your model. For YOLO models, outputs vary by implementation. - // For demonstration, let's assume single output with shape [num_detections, 6] - // where each row = [x, y, w, h, confidence, classIndex] - - const outputName = session.outputNames[0]; - const output = results[outputName]; - - if (!output || !(output.data instanceof Float32Array)) { - throw new Error('Unexpected model output format'); - } - - const data = output.data as Float32Array; - const numDetections = output.dims[0]; - const detections: DetectionOutput[] = []; - - for (let i = 0; i < numDetections; i++) { - const offset = i * 6; - const [x, y, w, h, confidence, classIdx] = [ - data[offset], - data[offset + 1], - data[offset + 2], - data[offset + 3], - data[offset + 4], - data[offset + 5] - ]; - - if (confidence > 0.3) { // threshold - detections.push({ - bbox: [x, y, w, h], - confidence, - classIndex: Math.round(classIdx), - }); - } - } - return detections; -} export async function writeLabels(outputPath: string, detectionsByFrame: Map, classNames: Record) { // Write labels in YOLO txt format per frame: @@ -147,73 +105,186 @@ export async function writeLabels(outputPath: string, detectionsByFrame: Map { const yamlContent = await readFile(yamlPath, 'utf8'); return yaml.load(yamlContent) as DataYaml; } -export async function vibeuiInference( - modelPath: string, - videoFilePath: string -): Promise { - if (!modelPath) throw new Error('missing modelPath, arg0'); - if (!videoFilePath) throw new Error('missing videoFilePath, arg1'); +/** + * Runs YOLO inference on the given video file using the configured model. + * + * - Prepares the Python environment and loads the YOLO model. + * - Generates a unique output directory for the results. + * - Executes YOLO with flags to save text labels and confidence scores (but not images). + * + * @param videoFilePath - Path to the input video file to analyze. + * @returns Path to the output directory containing the prediction results. + */ +export async function inference(videoFilePath: string): Promise { + await preparePython() + const spawn = await getNanoSpawn() - // Load ONNX model - console.log(`Loading ONNX model from ${modelPath}`); + const modelPath = join(env.VIBEUI_DIR, 'vibeui.pt') - const session = await ort.InferenceSession.create(modelPath); + // Generate a unique name based on video name + UUID + const uniqueName = nanoid() + const customProjectDir = 'runs' // or any custom folder + const outputPath = join(env.APP_DIR, customProjectDir, uniqueName) - // Prepare output dir - // const videoExt = extname(videoFilePath); - // const videoName = basename(videoFilePath, videoExt); - // const uniqueName = `${videoName}-${nanoid()}`; - const outputPath = join(env.CACHE_ROOT, nanoid()); + await spawn('./venv/bin/yolo', [ + 'predict', + `model=${modelPath}`, + `source=${videoFilePath}`, + 'save=False', + 'save_txt=True', + 'save_conf=True', + `project=${customProjectDir}`, + `name=${uniqueName}`, + ], { + cwd: env.APP_DIR, + stdio: 'inherit', + }) - - // Extract frames - const framesDir = join(outputPath, 'frames'); - mkdirSync(framesDir, { recursive: true }) - console.log(`Extracting video frames from ${videoFilePath} to ${framesDir}...`); - await extractFrames(videoFilePath, framesDir); - - // Load class names from data.yaml - const dataYaml = await loadDataYaml(join(env.VIBEUI_DIR, 'data.yaml')); - const classNames = dataYaml.names; - - // Read all frames and run inference - const frameFiles = (await readdir(framesDir)) - .filter(f => f.endsWith('.jpg')) - .sort(); - - console.log(`frameFiles=${JSON.stringify(frameFiles)}`) - const detectionsByFrame = new Map(); - - if (frameFiles.length === 0) throw new Error(`No frames extracted! This is likely a bug.`); - - console.log(`Running inference on ${frameFiles.length} frames...`); - - for (const file of frameFiles) { - const frameIndex = parseInt(file.match(/(\d+)\.jpg$/)?.[1] ?? '0', 10); - const imagePath = join(framesDir, file); - const inputTensor = await preprocessImage(imagePath); - const detections = await runInferenceOnFrame(session, inputTensor); - detectionsByFrame.set(frameIndex, detections); - } - - // Write YOLO format label txt files - await writeLabels(outputPath, detectionsByFrame, classNames); - - // Optionally cleanup frames dir to save space: - // await rmSync(framesDir, { recursive: true, force: true }); - - return outputPath; + return outputPath // contains labels/ folder and predictions } +// export async function runModelInference(session: ort.InferenceSession, inputTensor: ort.Tensor): Promise { +// const feeds = { input: inputTensor }; +// const results = await session.run(feeds); +// // Adjust 'output' to your model's output key +// const outputTensor = results.output; +// return postprocess(outputTensor); +// } + + +// export async function yoloInference(modelPath: string, videoFilePath: string) { + +// await preparePython() +// const spawn = await getNanoSpawn() + +// const uniqueName = nanoid() +// const customProjectDir = 'vibeui' // or any custom folder +// const outputPath = join(env.CACHE_ROOT, customProjectDir, uniqueName) + +// const predictionOutput = await spawn('./venv/bin/yolo', [ +// 'predict', +// `model=${modelPath}`, +// `source=${videoFilePath}`, +// 'save=False', +// 'save_txt=True', +// 'save_conf=True', +// `project=${customProjectDir}`, +// `name=${uniqueName}`, +// ], { +// cwd: env.VIBEUI_DIR, +// stdio: 'inherit', +// }) + +// return outputPath // contains labels/ folder and predictions +// console.log(`prediction output ${predictionOutput}`); + + +// const funscriptFilePath = await buildFunscript(helpers, predictionOutput, videoFilePath) + + +// const s3Key = `funscripts/${vodId}.funscript`; +// const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json"); + +// console.log(`Uploaded funscript to S3: ${s3Url}`); + + +// console.log(`Funscript saved to database for vod ${vodId}`); + +// } + +// export async function vibeuiInference( +// modelPath: string, +// videoFilePath: string +// ): Promise { + +// if (!modelPath) throw new Error('missing modelPath, arg0'); +// if (!videoFilePath) throw new Error('missing videoFilePath, arg1'); + +// // Load ONNX model +// console.log(`Loading ONNX model from ${modelPath}`); + +// const session = await ort.InferenceSession.create(modelPath); + +// console.log(`inputNames=${session.inputNames} outputNames=${session.outputNames}`) + +// // Prepare output dir +// // const videoExt = extname(videoFilePath); +// // const videoName = basename(videoFilePath, videoExt); +// // const uniqueName = `${videoName}-${nanoid()}`; +// const outputPath = join(env.CACHE_ROOT, nanoid()); + + +// // Extract frames +// const framesDir = join(outputPath, 'frames'); +// mkdirSync(framesDir, { recursive: true }) +// console.log(`Extracting video frames from ${videoFilePath} to ${framesDir}...`); +// await extractFrames(videoFilePath, framesDir); + +// // Load class names from data.yaml +// const dataYaml = await loadDataYaml(join(env.VIBEUI_DIR, 'data.yaml')); +// const classNames = dataYaml.names; + +// // Read all frames and run inference +// const frameFiles = (await readdir(framesDir)) +// .filter(f => f.endsWith('.jpg')) +// .sort(); + +// // console.log(`frameFiles=${JSON.stringify(frameFiles)}`) +// const detectionsByFrame = new Map(); + +// if (frameFiles.length === 0) throw new Error(`No frames extracted! This is likely a bug.`); + +// console.log(`Running inference on ${frameFiles.length} frames...`); + + +// for (const file of frameFiles) { +// const frameIndex = parseInt(file.match(/(\d+)\.jpg$/)?.[1] ?? '0', 10); +// const imagePath = join(framesDir, file); +// const inputTensor = await preprocessImage(imagePath); +// const detections = await runModelInference(session, inputTensor) +// console.log(`[frame ${frameIndex}] detections.length = ${detections.length}`); +// detectionsByFrame.set(frameIndex, detections); + +// } + +// // Write YOLO format label txt files +// await writeLabels(outputPath, detectionsByFrame, classNames); + +// // Optionally cleanup frames dir to save space: +// // await rmSync(framesDir, { recursive: true, force: true }); + +// return outputPath; +// } +/** + * Extracts video metadata (FPS and frame count) using ffprobe. + * + * - Spawns an ffprobe subprocess to analyze the video stream. + * - Retrieves the frame rate (`r_frame_rate`) and total frame count (`nb_read_frames`). + * - Parses and returns both values as numbers. + * + * @param videoPath - Path to the video file to analyze. + * @returns An object containing the video's frames per second (`fps`) and total number of frames (`frames`). + * @throws If ffprobe fails or returns malformed output. + */ export async function ffprobe(videoPath: string): Promise<{ fps: number; frames: number }> { const spawn = await getNanoSpawn() const { stdout } = await spawn('ffprobe', [ @@ -233,6 +304,41 @@ export async function ffprobe(videoPath: string): Promise<{ fps: number; frames: return { fps, frames } } + + + + + +// export async function getModelClasses(modelPath: string): Promise> { +// const jsonPath = modelPath.replace(/\.onnx$/, '.json'); + +// try { +// const data = await readJson(jsonPath); + +// if (data.labels && typeof data.labels === 'object') { +// // Return the labels object as-is, retaining numeric keys as strings +// return data.labels; +// } else { + +// throw new Error('Invalid labels format in JSON'); +// } +// } catch (err) { +// console.error(`Failed to read labels from ${jsonPath}:`, err); +// throw err; +// } +// } + + +/** + * Loads basic metadata from a video file using ffprobe. + * + * - Retrieves the video's frame rate (fps) and total frame count. + * - Logs the extracted metadata to the console. + * + * @param videoPath - Path to the video file to analyze. + * @returns An object containing `fps` and `totalFrames`. + * @throws If metadata extraction fails. + */ export async function loadVideoMetadata(videoPath: string) { const { fps, frames: totalFrames } = await ffprobe(videoPath); console.log(`Video metadata: fps=${fps}, frames=${totalFrames}`); @@ -241,24 +347,29 @@ export async function loadVideoMetadata(videoPath: string) { export async function processLabelFiles(labelDir: string, data: DataYaml): Promise { const labelFiles = (await readdir(labelDir)).filter(file => file.endsWith('.txt')); + console.log(`[processLabelFiles] Found label files: ${labelFiles.length}`); + if (labelFiles.length === 0) console.warn(`⚠️⚠️⚠️ no label files found! this should normally NOT happen unless the video contained no lovense overlay. ⚠️⚠️⚠️`); + const detections: Map = new Map(); const names = data.names; for (const file of labelFiles) { const match = file.match(/(\d+)\.txt$/); if (!match) { - console.log(`Skipping invalid filename: ${file}`); + console.log(`[processLabelFiles] Skipping invalid filename: ${file}`); continue; } + const frameIndex = parseInt(match[1], 10); if (isNaN(frameIndex)) { - console.log(`Skipping invalid frame index from filename: ${file}`); + console.log(`[processLabelFiles] Skipping invalid frame index: ${file}`); continue; } const content = await readFile(join(labelDir, file), 'utf8'); const lines = content.trim().split('\n'); const frameDetections: Detection[] = []; + let maxConfidence = 0; let selectedClassIndex = -1; @@ -268,6 +379,7 @@ export async function processLabelFiles(labelDir: string, data: DataYaml): Promi const classIndex = parseInt(parts[0], 10); const confidence = parseFloat(parts[5]); + if (isNaN(classIndex) || isNaN(confidence)) continue; if (confidence >= 0.7 && confidence > maxConfidence) { @@ -276,10 +388,13 @@ export async function processLabelFiles(labelDir: string, data: DataYaml): Promi } } - if (maxConfidence > 0) { - const className = (data.names as Record)[selectedClassIndex.toString()]; + if (maxConfidence > 0 && selectedClassIndex !== -1) { + const className = names[selectedClassIndex.toString()]; if (className) { + console.log(`[processLabelFiles] Frame ${frameIndex}: detected class "${className}" with confidence ${maxConfidence}`); frameDetections.push({ startFrame: frameIndex, endFrame: frameIndex, className }); + } else { + console.log(`[processLabelFiles] Frame ${frameIndex}: class index ${selectedClassIndex} has no name`); } } @@ -292,7 +407,7 @@ export async function processLabelFiles(labelDir: string, data: DataYaml): Promi const detectionSegments: Detection[] = []; let currentDetection: Detection | null = null; - for (const [frameIndex, frameDetections] of detections.entries()) { + for (const [frameIndex, frameDetections] of [...detections.entries()].sort((a, b) => a[0] - b[0])) { for (const detection of frameDetections) { if (!currentDetection || currentDetection.className !== detection.className) { if (currentDetection) detectionSegments.push(currentDetection); @@ -302,7 +417,13 @@ export async function processLabelFiles(labelDir: string, data: DataYaml): Promi } } } + if (currentDetection) detectionSegments.push(currentDetection); + console.log(`[processLabelFiles] Total detection segments: ${detectionSegments.length}`); + for (const segment of detectionSegments) { + console.log(` - Class "${segment.className}": frames ${segment.startFrame}–${segment.endFrame}`); + } + return detectionSegments; }