Compare commits

..
Author SHA1 Message Date
Michael Chung 8a5e4538a0 All good! going to merge now. 2023-10-25 11:32:22 -04:00
Michael Chung 3f70ca72dd Dev environment
Fixed various code problems, going to merge soon.
2023-10-24 13:09:36 -04:00
Michael Chung d8a4b6c735 Get everything to build again we have to merge soon. 2023-10-24 11:26:12 -04:00
Michael Chung 48ed6d118c Merge issues with VSCode? this is strange .... 2023-10-24 11:15:31 -04:00
Michael Chung 4c3ac3edda Merge branch 'master' into feature/enqueue_tts_request 2023-10-24 10:20:37 -04:00
Brandon Thomas dae5764658 codegen queries 2023-10-24 05:40:33 -04:00
Brandon Thomas 98547df063 propagate avt from jobs to media_files 2023-10-24 05:12:42 -04:00
Brandon Thomas 9c856235fc write avt cookie token to inference jobs 2023-10-24 05:04:00 -04:00
Brandon Thomas 205f6de1b2 fix lint failures 2023-10-24 04:20:38 -04:00
Brandon Thomas a9fa45575e additional comment 2023-10-24 04:07:02 -04:00
Brandon Thomas 1b77974a0e change user token prefix 2023-10-24 04:06:33 -04:00
Brandon Thomas 724ae2570e How did this ever work!? 2023-10-24 03:56:38 -04:00
Brandon Thomas dc7b5b7e60 Merge pull request #120 from storytold/echelon-terminate-job-endpoint
endpoint to terminate jobs
2023-10-24 02:41:03 -04:00
Brandon Thomas 3259433717 endpoint to terminate jobs 2023-10-24 02:40:00 -04:00
Brandon Thomas bc5d84a306 use the new job status enum 2023-10-24 01:22:48 -04:00
Brandon Thomas 2357f00944 Merge pull request #119 from storytold/echelon-job-system-new-states
Introduce two new job status types to generic inference jobs
2023-10-24 01:08:15 -04:00
Brandon Thomas 24127f20e4 Introduce two new job status types to generic inference jobs 2023-10-24 01:06:14 -04:00
Brandon Thomas 4c8f14d4d5 Migration to make password_resets.ip_address_redemption nullable 2023-10-23 22:11:26 -04:00
Brandon Thomas e14440ba02 undo edit to previous migration (should be harmless in prod) 2023-10-23 22:05:11 -04:00
Michael Chung 7295a3295f Fix prefixes for create and inference 2023-10-23 22:03:37 -04:00
Michael Chung 10176079c7 remove variables not used 2023-10-23 21:59:26 -04:00
Michael Chung 8999a80e92 Change root ml dir 2023-10-23 21:34:58 -04:00
Michael Chung 41b07049ff Remove comments 2023-10-23 21:29:41 -04:00
Michael Chung b45f6ed691 Restore storyteller rust root for dev_database_seed 2023-10-23 21:25:04 -04:00
Michael Chung 9d16eb05c1 Fix data seed env-secrets path. 2023-10-23 21:13:27 -04:00
Michael Chung b414540251 Fixing issue with the origin model type along side tests. 2023-10-23 21:11:00 -04:00
Michael Chung 2949456adc Restore bad merge on id_category.rs 2023-10-23 21:07:35 -04:00
Michael Chung 3a72292898 Some minor comment fix 2023-10-23 16:54:27 -04:00
Michael Chung 07c640ce84 Retest the endpoints with the correct credentials
One more integration test with multiple wav files.
2023-10-23 16:52:31 -04:00
Michael Chung 49a15fd1f1 Cleaning up some of the end points. 2023-10-23 16:22:37 -04:00
Michael Chung 3267f9949d Added ip address and creator token. 2023-10-23 16:02:07 -04:00
Michael Chung 47df6930d2 Basically works well!
Few things to checkout.
2023-10-22 23:38:31 -04:00
Michael Chung 913d282d60 Fixed extensions on create
Checking whether media uploads.
2023-10-22 20:52:57 -04:00
Michael Chung 743934ff50 Need to do a clean up then check media upload and table 2023-10-22 20:36:32 -04:00
Michael Chung bc209fe939 So the prefix wasn't populated in the seed I think! 2023-10-22 17:57:35 -04:00
Michael Chung 302975ddfd Seeded db testing again 2023-10-22 11:57:29 -04:00
Michael Chung d7664e8e1c Merge branch 'master' into feature/enqueue_tts_request 2023-10-21 02:41:43 -04:00
Michael Chung 9f7fc09e9f Builds testing. 2023-10-21 01:13:39 -04:00
Michael Chung 2686cb94e0 Testing create command now. 2023-10-21 00:28:11 -04:00
Michael Chung fd7f1e1893 testing now. 2023-10-20 23:27:31 -04:00
Brandon Thomas eb3499596e always output stderr 2023-10-20 14:45:03 -04:00
Michael Chung 00bfdad3d0 Test pass! 2023-10-20 12:13:57 -04:00
Michael Chung ff3821956a Builds again 2023-10-20 11:43:16 -04:00
Michael Chung a5a5f5473b Testing! 2023-10-20 10:13:23 -04:00
Brandon Thomas 7c553ffcee fix rvc jobs 2023-10-20 07:00:09 -04:00
Brandon Thomas 52f0b44c26 codegen db 2023-10-20 06:14:49 -04:00
Brandon Thomas fbed7cd530 Merge pull request #113 from storytold/echelon-voice-conversion-media-files
voice conversion --> media files
2023-10-20 06:14:19 -04:00
Brandon Thomas 4ce8752a6a codegen db 2023-10-20 06:12:41 -04:00
Brandon Thomas 3239e318b1 fix inference job status links 2023-10-20 05:37:51 -04:00
Brandon Thomas 471dcff697 RVC -> media_files 2023-10-20 05:14:00 -04:00
Brandon Thomas 2af57fcf3e Write voice conversion results to media_files tables 2023-10-20 05:14:00 -04:00
Brandon Thomas f2b0e77210 fix stupid "1" bug on generic jobs 2023-10-20 05:13:44 -04:00
Michael Chung 10c8bc1ef3 Just need to run inference and pass the insert the record and upload the voice once it infers.
Run the path test.
2023-10-20 01:46:13 -04:00
Brandon Thomas 35dfe6a7f2 fix lints 2023-10-20 01:09:56 -04:00
Brandon Thomas 48ecc44978 Merge pull request #112 from storytold/echelon-seed-samples
Update seed tool to seed and upload samples
2023-10-19 22:36:30 -04:00
Brandon Thomas 4f0e2d5f72 Update seed tool to seed and upload samples 2023-10-19 22:33:24 -04:00
Brandon Thomas 96c99fd102 Merge pull request #111 from storytold/echelon-media-file-upload-cli
CLI tool to upload media files and save them to the DB
2023-10-19 21:56:38 -04:00
Brandon Thomas 26794b3d2e CLI tool to upload media files and save them to the DB 2023-10-19 21:52:32 -04:00
Michael Chung c3a60ed8ab Merge branch 'master' into feature/enqueue_tts_request 2023-10-19 20:12:40 -04:00
Michael Chung 13964901f0 update process job created a fork for creating voice 2023-10-19 19:19:53 -04:00
Brandon Thomas 593fb50fcb Merge pull request #110 from storytold/echelon-list-dataset-samples
Enrich list dataset samples query + endpoint with bucket information
2023-10-19 18:24:39 -04:00
Brandon Thomas fff71d7aa4 Enrich list dataset samples query + endpoint with bucket information 2023-10-19 18:18:35 -04:00
Michael Chung 57eecb3757 Creating the create voice job 2023-10-19 16:26:43 -04:00
Brandon Thomas 022aa523cb fix cookie paths ? 2023-10-19 05:56:15 -04:00
Brandon Thomas 6d01506bd1 fix cookie path 2023-10-19 05:53:44 -04:00
Brandon Thomas 0cc3baee27 Merge pull request #108 from storytold/brandon-set-avt-cookie
Start setting AVT cookie on /v1/session endpoint
2023-10-19 05:06:00 -04:00
Brandon Thomas d5b28d2d3e Start setting AVT cookie on /v1/session endpoint 2023-10-19 04:24:50 -04:00
Brandon Thomas d6a3d4887f Merge pull request #107 from storytold/bt-revert-sha2-upgrade
Revert "Bump sha2 from 0.9.5 to 0.10.5"
2023-10-19 02:44:56 -04:00
Brandon Thomas cce4f5f3b7 Revert "Bump sha2 from 0.9.5 to 0.10.5"
This reverts commit 59f7b6f732.
2023-10-19 02:44:21 -04:00
Brandon Thomas 9123dbc3d9 Merge pull request #98 from storytold/dependabot/cargo/sha2-0.10.5
Bump sha2 from 0.9.5 to 0.10.5
2023-10-19 02:41:04 -04:00
Brandon Thomas d43a747033 Merge pull request #100 from storytold/dependabot/cargo/rpassword-7.2.0
Bump rpassword from 5.0.1 to 7.2.0
2023-10-19 02:40:25 -04:00
Brandon Thomas c3e5b42bf3 use JwtSigner for session cookie 2023-10-19 02:39:17 -04:00
Michael Chung 25cdbf2f1d Adding create voice command 2023-10-19 02:09:16 -04:00
dependabot[bot] 59f7b6f732 Bump sha2 from 0.9.5 to 0.10.5
Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.9.5 to 0.10.5.
- [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.9.5...sha2-v0.10.5)

---
updated-dependencies:
- dependency-name: sha2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-19 05:57:20 +00:00
dependabot[bot] fe7251744f Bump rpassword from 5.0.1 to 7.2.0
Bumps [rpassword](https://github.com/conradkleinespel/rpassword) from 5.0.1 to 7.2.0.
- [Release notes](https://github.com/conradkleinespel/rpassword/releases)
- [Commits](https://github.com/conradkleinespel/rpassword/compare/v5.0.1...v7.2.0)

---
updated-dependencies:
- dependency-name: rpassword
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-19 05:56:56 +00:00
Brandon Thomas fdd60b436a Merge pull request #99 from storytold/dependabot/cargo/scraper-0.17.1
Bump scraper from 0.14.0 to 0.17.1
2023-10-19 01:55:06 -04:00
Brandon Thomas 0836e88f4c Merge pull request #101 from storytold/dependabot/cargo/diesel-2.1.3
Bump diesel from 1.4.6 to 2.1.3
2023-10-19 01:54:46 -04:00
Brandon Thomas 261978f763 Merge pull request #102 from storytold/dependabot/cargo/anyhow-1.0.75
Bump anyhow from 1.0.40 to 1.0.75
2023-10-19 01:53:55 -04:00
Brandon Thomas d072e021d1 Merge pull request #106 from storytold/echelon-cookies
Cookie stuff - JWT signer, anonymous visitor cookies, etc.
2023-10-19 01:53:05 -04:00
Brandon Thomas 66442d9eda Cookie stuff - JWT signer, anonymous visitor cookies, etc.
- JWT signer is reusable, tested

- AVT cookies improve the anonymous user experience and will help
  internal analytics
2023-10-19 01:37:50 -04:00
Michael Chung 0f4cab9ca3 Added missing new file 2023-10-18 19:50:24 -04:00
Michael Chung 6de4d451ac Fixed import issues 2023-10-18 19:50:07 -04:00
Michael Chung 9d4e426ace It is now being tested then we work on the command side. 2023-10-18 18:02:30 -04:00
Michael Chung bfb5103f46 Merge branch 'master' into feature/enqueue_tts_request 2023-10-18 13:37:23 -04:00
Michael Chung 3308c05836 Need to pull master 2023-10-18 13:26:19 -04:00
Brandon Thomas 5a539e589d codegen db 2023-10-18 04:53:55 -04:00
Brandon Thomas 604c72179a password_resets needs a unique index on (user, secret_key) 2023-10-18 02:22:39 -04:00
Michael Chung be19eefa1a Upload and create record and were good to do the other command and clean up. 2023-10-18 02:13:59 -04:00
Michael Chung 34e2b1e544 It works runs inference_job
Need to upload the file then create the record for download
2023-10-18 02:03:41 -04:00
Brandon Thomas 95152e9a88 fix replacement paths 2023-10-18 00:31:43 -04:00
Michael Chung cbe8aaa1ba More fixes 2023-10-18 00:04:33 -04:00
Michael Chung 11185584a7 Fixing typos and virtual env 2023-10-17 22:56:30 -04:00
Michael Chung 76559cf783 fix the env 2023-10-17 22:11:22 -04:00
Michael Chung 2e7bd622f3 fixed a typo 2023-10-17 22:06:42 -04:00
Michael Chung 68048659d4 Testing inference_job 2023-10-17 22:00:14 -04:00
Brandon Thomas 608e94a6a8 Merge pull request #105 from storytold/echelon-config-path-substitution
Substitute config absolute paths with magic substitution strings
2023-10-17 21:38:06 -04:00
Brandon Thomas 9e0bee8fba Substitute config absolute paths with magic substitution strings 2023-10-17 21:37:20 -04:00
Brandon Thomas dcec9b9e8a Merge pull request #104 from storytold/echelon-storyteller-home
"storyteller root" directory in development
2023-10-17 21:12:51 -04:00
Brandon Thomas 3fc0f45942 "storyteller root" directory in development 2023-10-17 21:04:54 -04:00
Brandon Thomas bfd325900f Merge pull request #103 from storytold/echelon-better-envvars
Better env var support
2023-10-17 17:00:54 -04:00
Brandon Thomas 1ef7ae1009 Better env var support 2023-10-17 16:31:53 -04:00
Michael Chung 17d51f8d87 Merge branch 'master' into feature/enqueue_tts_request 2023-10-17 13:37:35 -04:00
Brandon Thomas ca81d1b543 fix build / lint errors 2023-10-16 20:02:41 -04:00
dependabot[bot] 1de3e669d6 Bump anyhow from 1.0.40 to 1.0.75
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.40 to 1.0.75.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.40...1.0.75)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 22:18:42 +00:00
dependabot[bot] ac39ac0a76 Bump diesel from 1.4.6 to 2.1.3
Bumps [diesel](https://github.com/diesel-rs/diesel) from 1.4.6 to 2.1.3.
- [Release notes](https://github.com/diesel-rs/diesel/releases)
- [Changelog](https://github.com/diesel-rs/diesel/blob/v2.1.3/CHANGELOG.md)
- [Commits](https://github.com/diesel-rs/diesel/compare/v1.4.6...v2.1.3)

---
updated-dependencies:
- dependency-name: diesel
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 22:18:25 +00:00
dependabot[bot] f9caa7d836 Bump scraper from 0.14.0 to 0.17.1
Bumps [scraper](https://github.com/causal-agent/scraper) from 0.14.0 to 0.17.1.
- [Release notes](https://github.com/causal-agent/scraper/releases)
- [Commits](https://github.com/causal-agent/scraper/compare/v0.14.0...v0.17.1)

---
updated-dependencies:
- dependency-name: scraper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 22:17:50 +00:00
Michael Chung 5f7a10a54c Merge branch 'master' into feature/enqueue_tts_request 2023-10-16 09:34:46 -04:00
Brandon Thomas e478c73ddf Merge pull request #97 from storytold/echelon-sample-upload
Dataset sample upload (not yet tested, but compiles, and needs lots of cleanup)
2023-10-14 12:23:36 -04:00
Brandon Thomas 92676e842c Dataset sample upload 2023-10-14 12:18:42 -04:00
Michael Chung 7eee225296 Builds again need to clearify what happened to the download function 2023-10-13 15:36:21 -04:00
Michael Chung 1319471c04 Merge branch 'master' into feature/enqueue_tts_request 2023-10-13 10:02:17 -04:00
Brandon Thomas 47e7269880 codegen db 2023-10-13 02:50:15 -04:00
Brandon Thomas 9b83caece1 Merge pull request #96 from storytold/echelon-get-media-file-endpoint
v1 of media_file GET endpoint.
2023-10-13 02:40:39 -04:00
Brandon Thomas 138057e105 v1 of media_file GET endpoint.
Media files are used for inference outputs, file uploads, Zero Shot
files, etc. We don't have any of the basic CRUD operations around them
yet, so this is a start.

This endpoint will need more metadata - moderation, file provenance,
file details, etc. But this will do for now.
2023-10-13 02:38:34 -04:00
Brandon Thomas 3e8b6f39fe Merge branch 'master' into feature/enqueue_tts_request 2023-10-12 23:28:08 -04:00
Brandon Thomas 63b4a3180f filter out sadtalker name 2023-10-12 06:22:39 -04:00
Brandon Thomas 6842794af6 another face detection failure 2023-10-12 06:15:43 -04:00
Brandon Thomas a963e5146a more instances of face detection failure 2023-10-12 05:33:56 -04:00
Brandon Thomas eb65ed5fa8 re-codegen db 2023-10-12 03:52:12 -04:00
Brandon Thomas f6989230be write origin_product_category 2023-10-12 03:51:01 -04:00
Brandon Thomas 2d3f29139a re-codegen db 2023-10-12 02:53:48 -04:00
Brandon Thomas a059aa7271 fix lints 2023-10-12 02:08:13 -04:00
Brandon Thomas 8699a9e342 record and report frontend_failure_category 2023-10-12 02:04:29 -04:00
Brandon Thomas 48bf168d99 improve readability 2023-10-12 01:14:03 -04:00
Brandon Thomas f1fd99be15 record frontend_failure_category, emit SadTalker errors 2023-10-12 01:03:36 -04:00
Michael Chung a0b8849806 Trying to build again. 2023-10-12 00:56:50 -04:00
Brandon Thomas 49db299f96 enums for two new columns 2023-10-11 23:09:18 -04:00
Brandon Thomas b1e87b7d90 two migrations (media_files, generic_inference_jobs)
- media_files.origin_product_category
- generic_inference_jobs.frontend_failure_category
2023-10-11 22:38:23 -04:00
Michael Chung bb0a4958ef Need to build and fix the container. 2023-10-11 18:19:40 -04:00
Brandon Thomas 4aacc23101 kill sadtalker jobs 2023-10-11 17:31:41 -04:00
Brandon Thomas 536307c162 analytics queries 2023-10-11 17:11:34 -04:00
Brandon Thomas d5c86d1345 fix breakage due to s3 client upgrade (YOLO) + lint fixes 2023-10-11 16:53:37 -04:00
Brandon Thomas 1900a31541 Merge pull request #66 from storytold/dependabot/cargo/rust-s3-0.33.0
Bump rust-s3 from 0.32.3 to 0.33.0
2023-10-11 16:26:24 -04:00
Brandon Thomas 067538f1c2 Merge pull request #88 from storytold/oct-10-mithoo
use usernames to list datasets/voices & simple handler for listing samples
2023-10-11 16:19:21 -04:00
Michael Chung a256681f6d Merge branch 'master' into feature/enqueue_tts_request 2023-10-11 12:58:57 -04:00
kasisnu 03443be19c inventory list voices with pagination 2023-10-11 16:52:37 +05:30
Michael Chung ec03420efc Fixed issue with typo in job.
Need to fix process job and run it.
2023-10-11 02:51:47 -04:00
Brandon Thomas bfc8171fa7 additional safeguards 2023-10-11 00:02:36 -04:00
Brandon Thomas 248ee45d11 multithreaded 2023-10-10 23:49:43 -04:00
Brandon Thomas 97be5da1b5 Truncate bucket hash for seeded zero shot voice records 2023-10-10 22:06:16 -04:00
Brandon Thomas d26902911f Merge pull request #93 from storytold/feature/fix-database-seed-voice-embeddings
Fixed bucket hash issue
2023-10-10 22:00:27 -04:00
Michael Chung 0560a2d607 Fixed bucket hash issue 2023-10-10 20:34:27 -04:00
Michael Chung 264058ea87 Just a quick commit gotta modify the seeding script to get the bucket hashes for downloading 2023-10-10 20:20:56 -04:00
Brandon Thomas b175cc0e65 cleanup more statuses 2023-10-10 19:24:07 -04:00
Brandon Thomas ae781a3e37 rename to kubectl- to not collide with base tool in tab complete 2023-10-10 19:15:53 -04:00
Brandon Thomas ee00fbe585 cleanup pods with these statuses 2023-10-10 19:12:39 -04:00
Brandon Thomas 82791ec39e delete pods randomly 2023-10-10 18:51:35 -04:00
Brandon Thomas b6bbc76b18 delete batches 2023-10-10 18:24:57 -04:00
Brandon Thomas 1742827ed9 ergonomics 2023-10-10 18:01:06 -04:00
Brandon Thomas 68bc9d0bb0 Merge pull request #89 from storytold/echelon-kubectl-cli
kubectl cli to cleanup dead pods
2023-10-10 17:51:12 -04:00
Brandon Thomas ccc67d43cc kubectl cli to cleanup dead pods 2023-10-10 17:50:05 -04:00
Michael Chung 3845c632b2 Turns out we don't support folder downloads only files. 2023-10-10 17:40:33 -04:00
Michael Chung 22518d9164 Fixed pathing typos 2023-10-10 16:24:16 -04:00
Michael Chung 5dbed7afbb Fixed typo on downloading the vall-e-x model 2023-10-10 16:18:35 -04:00
Michael Chung a485666b1c Test pass!
Payload delivered and picked up.
Need to ensure the job now runs locally.
2023-10-10 16:03:27 -04:00
Michael Chung 54e9b8af70 Fixed routing issue with the job need to move tts text to maybe tts text out of the json. 2023-10-10 15:32:51 -04:00
kasisnu 5a7b0b1bdd simple list dataset samples 2023-10-10 19:15:58 +05:30
kasisnu ee0067161e use usernames instead of user tokens to list voices/datasets 2023-10-10 18:03:22 +05:30
Brandon Thomas a0f464e454 Merge pull request #87 from storytold/echelon-dataset-endpoints
Dataset endpoints, refactoring, cleanup, etc.
2023-10-10 03:22:21 -04:00
Brandon Thomas 332982faa5 Dataset endpoints, refactoring, cleanup, etc. 2023-10-10 03:16:11 -04:00
Brandon Thomas c0e142d668 RMVPE support 2023-10-10 01:18:12 -04:00
Brandon Thomas ca8dce4805 re-codegen db 2023-10-09 23:58:09 -04:00
Brandon Thomas ed1eb9a540 stop dependabot from suggesting /old_code fixes (maybe delete all this?) 2023-10-09 23:30:16 -04:00
Brandon Thomas 0620fa6f98 extra tests for previously broken upgrade 2023-10-09 23:15:09 -04:00
Brandon Thomas 94adc01d62 Merge pull request #86 from storytold/echelon-cleanup-identifiers
Cleanup identifiers (tokens package)
2023-10-09 23:02:15 -04:00
Brandon Thomas 6e76cd3da6 Cleanup identifiers (tokens package) 2023-10-09 23:00:11 -04:00
Brandon Thomas 5a1fd2679c fix for broken dependabot base64 upgrade (semvar violation) 2023-10-09 22:25:38 -04:00
dependabot[bot] f5c3e12f90 Bump rust-s3 from 0.32.3 to 0.33.0
Bumps [rust-s3](https://github.com/durch/rust-s3) from 0.32.3 to 0.33.0.
- [Release notes](https://github.com/durch/rust-s3/releases)
- [Commits](https://github.com/durch/rust-s3/commits/v0.33.0)

---
updated-dependencies:
- dependency-name: rust-s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 02:02:36 +00:00
Brandon Thomas 0a141ea118 Merge pull request #84 from storytold/dependabot/cargo/cidr-utils-0.5.11
Bump cidr-utils from 0.5.10 to 0.5.11
2023-10-09 22:01:02 -04:00
Brandon Thomas dd6c5d1975 Merge pull request #82 from storytold/dependabot/cargo/base64-0.21.0
Bump base64 from 0.13.0 to 0.21.0
2023-10-09 22:00:40 -04:00
Brandon Thomas 91dcd1f876 Merge pull request #83 from storytold/dependabot/cargo/unicode-segmentation-1.10.1
Bump unicode-segmentation from 1.7.1 to 1.10.1
2023-10-09 22:00:08 -04:00
Brandon Thomas 1869ead6ad Merge pull request #85 from storytold/dependabot/cargo/futures-util-0.3.28
Bump futures-util from 0.3.26 to 0.3.28
2023-10-09 21:59:34 -04:00
Brandon Thomas 1c81874b28 fix tests and lints 2023-10-09 21:55:48 -04:00
Brandon Thomas c8b79bfb40 cleanup logic 2023-10-09 21:44:14 -04:00
Brandon Thomas 767d76f831 comments about dev bucket 2023-10-09 21:04:36 -04:00
Brandon Thomas b163791db2 Merge pull request #77 from storytold/feature/enqueue_tts_request
Feature/enqueue tts request
2023-10-09 21:02:26 -04:00
Brandon Thomas d4e8bfb1f8 Merge pull request #79 from storytold/oct-06-mithoo
adds list dataset handler and update/delete voices handler
2023-10-09 20:58:25 -04:00
dependabot[bot] fabc1583ca Bump futures-util from 0.3.26 to 0.3.28
Bumps [futures-util](https://github.com/rust-lang/futures-rs) from 0.3.26 to 0.3.28.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.26...0.3.28)

---
updated-dependencies:
- dependency-name: futures-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 23:08:03 +00:00
dependabot[bot] 804ab3e4e8 Bump cidr-utils from 0.5.10 to 0.5.11
Bumps [cidr-utils](https://github.com/magiclen/cidr-utils) from 0.5.10 to 0.5.11.
- [Commits](https://github.com/magiclen/cidr-utils/compare/v0.5.10...v0.5.11)

---
updated-dependencies:
- dependency-name: cidr-utils
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 23:07:31 +00:00
dependabot[bot] cd0e104808 Bump unicode-segmentation from 1.7.1 to 1.10.1
Bumps [unicode-segmentation](https://github.com/unicode-rs/unicode-segmentation) from 1.7.1 to 1.10.1.
- [Commits](https://github.com/unicode-rs/unicode-segmentation/compare/1.7.1...v1.10.1)

---
updated-dependencies:
- dependency-name: unicode-segmentation
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 23:07:00 +00:00
dependabot[bot] a7d794e29b Bump base64 from 0.13.0 to 0.21.0
Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.13.0 to 0.21.0.
- [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.13.0...v0.21.0)

---
updated-dependencies:
- dependency-name: base64
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 23:05:57 +00:00
kasisnu eed7dc28f8 adds simple voice list endpoint 2023-10-09 18:33:07 +05:30
kasisnu d4c5710513 filter private/hidden datasets, make user token non-optional 2023-10-09 12:26:54 +05:30
Michael Chung d8c4df4c02 Ok fixed the odd linting error. 2023-10-06 18:12:04 -04:00
Michael Chung 13809ad309 Fixed issue 2023-10-06 18:04:46 -04:00
Michael Chung 95888e683d Formatter works now, braces can get properly placed 2023-10-06 18:01:25 -04:00
Michael Chung 3012dea984 process_single_tts_job augmented... 2023-10-06 17:58:07 -04:00
Michael Chung ae899d8aca Fixed most of the job and implemented it.
Need to run the container this might be fun haha ...
2023-10-06 15:21:38 -04:00
Michael Chung dda05ba22c Have to pull master for the lastest seed changes 2023-10-06 13:01:17 -04:00
Brandon Thomas 63795b2cb6 Merge pull request #81 from storytold/echelon-test-weights
Add zero shot weights and upload six test files; add to db seed tool
2023-10-06 12:51:20 -04:00
Brandon Thomas 8aa97a6a4f Add zero shot weights and upload six test files; add to db seed tool 2023-10-06 12:50:02 -04:00
Michael Chung e23369761b Merge branch 'master' into feature/enqueue_tts_request 2023-10-06 11:35:11 -04:00
Brandon Thomas 2b27d6fe41 Merge pull request #80 from storytold/echelon-seed-tool-2
More seed tool things
2023-10-06 11:30:14 -04:00
Michael Chung c6eefc41ec Ok fixed the build now working on job running. 2023-10-06 10:55:51 -04:00
Michael Chung 9e3a3b79f9 job process wip 2023-10-06 09:49:09 -04:00
kasisnu 2aa063c354 some meat on the list datasets handler - filtering logic needs wdork 2023-10-06 18:04:44 +05:30
kasisnu f77d4a636b skip mod token when creating datasets 2023-10-06 16:07:29 +05:30
Brandon Thomas 018b05a3a2 Seed voice conversion models 2023-10-06 02:50:12 -04:00
kasisnu fd3661e25d list/delete voices simple handlers 2023-10-06 12:07:51 +05:30
Brandon Thomas 39de5aba13 More updates to seed tool 2023-10-06 01:30:43 -04:00
Brandon Thomas 6354e7c3b4 Merge pull request #78 from storytold/echelon-db-seeding
Database seed tool
2023-10-06 01:17:59 -04:00
Brandon Thomas eaa9ddd62d seed voice 2023-10-06 00:51:52 -04:00
Michael Chung 195a2eeb9c Outlined the things needed to be done in process_job 2023-10-06 00:49:42 -04:00
Brandon Thomas bef5dce947 seed dataset 2023-10-06 00:36:15 -04:00
Brandon Thomas dd3f9c9d3e move query modules 2023-10-06 00:19:41 -04:00
Brandon Thomas aac31f77ad Database seed tool 2023-10-06 00:09:42 -04:00
Brandon Thomas d07a147db9 Merge pull request #62 from storytold/feat-create-dataset
create zs dataset endpoint - basic impl
2023-10-06 00:03:47 -04:00
Michael Chung ba76acec35 some more fixes to model downloaders 2023-10-05 23:05:27 -04:00
Michael Chung a2c196587f Added Inference Command Stub
Added Create Embedding Command Stub
Need to implement job process:
Download Embedding File aka voice token.
model_downloaders is all good.
validate_job.
2023-10-05 22:29:25 -04:00
Brandon Thomas 8d36d6c709 Add some downloaders for vall-e-x 2023-10-05 21:43:36 -04:00
Michael Chung 4f5f6cfe51 Getting the pieces ready for inference_job 2023-10-05 13:29:51 -04:00
kasisnu 7c59f267fc placeholder sql query to create a voice 2023-10-05 17:41:44 +05:30
kasisnu 23a6daa144 list handler questions 2023-10-05 16:34:36 +05:30
kasisnu a22038ea31 delete datasets & allow mods to undelete 2023-10-05 15:59:56 +05:30
Michael Chung 5de40b2dab Fix a build issues the payload sends exploring the job creation and inference side of it. 2023-10-04 16:30:46 -04:00
kasisnu 484e6788e3 enforce user token check 2023-10-04 19:02:16 +05:30
kasisnu b67cfb5fbe basic update dataset handler & synthetic id tracking 2023-10-04 18:03:13 +05:30
Brandon Thomas d46075a2a3 codegen 2023-10-04 03:58:05 -04:00
Brandon Thomas aa9b834f4b Merge pull request #76 from storytold/echelon-add-media-file-extension
Add media prefix and file extension
2023-10-04 03:50:00 -04:00
Brandon Thomas 2abba4b639 populate prefix and extension 2023-10-04 03:34:43 -04:00
kasisnu c42c091b2d create zs dataset endpoint - basic impl 2023-10-04 12:32:58 +05:30
Brandon Thomas cde8447a9c add table for bucket prefix 2023-10-04 02:33:28 -04:00
Brandon Thomas 4306a4763d Add extension 2023-10-04 02:24:28 -04:00
Brandon Thomas 9701e29b58 Migration to add file extension (eg. ".mp4") 2023-10-04 02:24:28 -04:00
Brandon Thomas 8512846efa Merge pull request #75 from storytold/bt-revert-sqlx-upgrade
Revert "Bump sqlx-core from 0.6.2 to 0.7.2"
2023-10-04 02:23:09 -04:00
Brandon Thomas c7b54e1548 Revert "Bump sqlx-core from 0.6.2 to 0.7.2"
This reverts commit 6b8c1a3106.
2023-10-04 02:15:54 -04:00
Brandon Thomas 8343cf1b65 Merge pull request #70 from storytold/dependabot/cargo/sqlx-core-0.7.2
Bump sqlx-core from 0.6.2 to 0.7.2
2023-10-04 02:04:06 -04:00
Brandon Thomas 4d4b55d39d Merge pull request #68 from storytold/dependabot/cargo/once_cell-1.18.0
Bump once_cell from 1.17.0 to 1.18.0
2023-10-04 02:03:54 -04:00
dependabot[bot] 6b8c1a3106 Bump sqlx-core from 0.6.2 to 0.7.2
Bumps [sqlx-core](https://github.com/launchbadge/sqlx) from 0.6.2 to 0.7.2.
- [Changelog](https://github.com/launchbadge/sqlx/blob/main/CHANGELOG.md)
- [Commits](https://github.com/launchbadge/sqlx/commits)

---
updated-dependencies:
- dependency-name: sqlx-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 06:03:43 +00:00
Brandon Thomas 63b3cb8216 Merge pull request #67 from storytold/dependabot/cargo/url-2.4.1
Bump url from 2.3.1 to 2.4.1
2023-10-04 02:03:25 -04:00
Brandon Thomas 3d4522126e Merge pull request #65 from storytold/dependabot/cargo/openssl-0.10.57
Bump openssl from 0.10.42 to 0.10.57
2023-10-04 02:02:33 -04:00
Brandon Thomas 8be1b5afa3 Merge pull request #69 from storytold/dependabot/cargo/actix-rt-2.9.0
Bump actix-rt from 2.7.0 to 2.9.0
2023-10-04 02:02:15 -04:00
dependabot[bot] 11f6995942 Bump actix-rt from 2.7.0 to 2.9.0
Bumps [actix-rt](https://github.com/actix/actix-net) from 2.7.0 to 2.9.0.
- [Release notes](https://github.com/actix/actix-net/releases)
- [Commits](https://github.com/actix/actix-net/compare/rt-v2.7.0...rt-v2.9.0)

---
updated-dependencies:
- dependency-name: actix-rt
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 05:56:36 +00:00
dependabot[bot] 589d13fdd1 Bump once_cell from 1.17.0 to 1.18.0
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.17.0 to 1.18.0.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.17.0...v1.18.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 05:56:02 +00:00
dependabot[bot] 3f9160701f Bump url from 2.3.1 to 2.4.1
Bumps [url](https://github.com/servo/rust-url) from 2.3.1 to 2.4.1.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.3.1...v2.4.1)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 05:55:30 +00:00
Brandon Thomas 9e8c27edfd Create dependabot.yml 2023-10-04 01:53:23 -04:00
dependabot[bot] 6540aed9dc Bump openssl from 0.10.42 to 0.10.57
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.42 to 0.10.57.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.42...openssl-v0.10.57)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 05:53:08 +00:00
Brandon Thomas 7cd570083c Merge pull request #64 from storytold/bt-misc-fix
fixing a few things
2023-10-04 01:10:15 -04:00
Brandon Thomas 8787e3ef1e tests for lipsync payload 2023-10-04 01:09:40 -04:00
Brandon Thomas 49b25cc79d fix query cache codegen 2023-10-04 01:09:40 -04:00
Brandon Thomas eff73a9cff actually check premium plan 2023-10-04 01:09:40 -04:00
Brandon Thomas d0e3e0f6bb Merge pull request #63 from storytold/bt-twitter-dimensions
SadTalker: Final API shape. Twitter dimensions, non-default options are opt-in, premium watermark
2023-10-04 00:31:00 -04:00
Brandon Thomas e676df0bf4 premium plan features 2023-10-04 00:26:52 -04:00
Brandon Thomas ebed726768 Resize SadTalker to "twitter" dimensions 2023-10-04 00:26:52 -04:00
Michael Chung e0145f0e70 Test this endpoint ensure that the record is created and you can see it grabbed. 2023-10-03 19:09:09 -04:00
Brandon Thomas 2f3037514f takedown requests 2023-10-03 13:38:13 -04:00
Michael Chung f7c636cf58 Added TTS payloads should be able to enter a entry after a migration then follow the event
to the inference dispatch and fill out the code there.
2023-10-02 23:56:52 -04:00
Michael Chung ec4a172929 Adding generic inference args and creating the job soon 2023-10-02 23:08:28 -04:00
Michael Chung 773b96fb35 Stubbing out work in the handler
Adding VallEX as a inference model type
Test pass
2023-10-02 21:45:40 -04:00
Michael Chung 40d0d0d844 Changing up enqueue_infer_tts_handler to allow embedding tokens. 2023-10-02 20:17:36 -04:00
Brandon Thomas dbae9803e2 Merge pull request #61 from storytold/testing-and-images-libs
Libraries for testing and image processing
2023-10-02 16:21:28 -04:00
Brandon Thomas 87093bf291 Libraries for testing and image processing
Just getting started here.
2023-10-02 16:20:07 -04:00
Michael Chung 0b3ea3af2a Working on enqueue_tts_request assuming the prompt is around. 2023-10-02 16:15:25 -04:00
ArEnSc 1a75d5b7b3 Merge pull request #60 from storytold/feature/postman-collections
Postman Collections
2023-10-02 14:58:16 -04:00
Michael Chung fb5dbae029 Added the GPT4Prompt for generating the collections and posted some relevant end points. 2023-10-02 13:41:06 -04:00
Brandon Thomas d2fba4349d fix broken lint 2023-10-01 17:17:43 -04:00
Brandon Thomas b76b4460e3 forgot to codegen after leaderboard query adjustment 2023-10-01 17:10:49 -04:00
Brandon Thomas 5fee53d7c7 Merge pull request #59 from storytold/echelon-sadtalker-options
More options for SadTalker
2023-10-01 17:07:33 -04:00
ArEnSc 4f589cd1b7 Merge pull request #58 from storytold/feature/Zeroshot-inference-job1
Feature/Stubs for Voice Designer?
2023-10-01 16:53:35 -04:00
Michael Chung 5b9f1551ee Put stubs behind feature flag. 2023-10-01 16:51:14 -04:00
Michael Chung e47125f12d Nested the endpoints wrong because to many ))) and got confused. 2023-10-01 15:04:01 -04:00
Michael Chung afa050b45e Testing routes 2023-10-01 13:44:22 -04:00
Brandon Thomas ab6986e4b4 Merge pull request #57 from storytold/echelon-hide-leaderboard
Hide Vegito's test account from TTS leaderboard
2023-10-01 05:45:20 -04:00
Brandon Thomas 53626cb312 More options for SadTalker 2023-10-01 05:07:56 -04:00
Brandon Thomas a8810a2db8 Hide Vegito's account from TTS leaderboard 2023-09-30 11:07:08 -04:00
Michael Chung cb8266d61e Run then test end points for the responses 2023-09-30 01:43:56 -04:00
Michael Chung 056065458f Early stubs 2023-09-30 01:43:25 -04:00
Michael Chung 7cb18d63f2 Initial stubs for the api 2023-09-30 01:27:36 -04:00
Michael Chung 12a119cc1b Routing for the backend start 2023-09-29 20:30:09 -04:00
Brandon Thomas c8d8546c57 Merge pull request #56 from storytold/echelon-zero-shot-tables
Zero shot tables
2023-09-29 00:10:16 -04:00
Brandon Thomas 3265e097c0 Zero shot tables 2023-09-28 23:45:31 -04:00
Brandon Thomas 695d3da34b analytics query 2023-09-28 10:22:38 -04:00
Brandon Thomas 6733a19315 Merge pull request #55 from storytold/echelon-face-detection-early-failure
Do not respawn SadTalker jobs when face detection fails
2023-09-28 10:20:23 -04:00
Brandon Thomas baefb9f7d6 Do not respawn SadTalker jobs when face detection fails
Currently SadTalker jobs will retry on failure, which is great for
worker nodes with transient issues. Unfortunately failure to detect a
face is a common user input error occuring in just around half of all
image uploads. This will permanently tombstone these jobs.

The new failure class can be reused for future animation systems that
rely on face detection.

There is still some minor work to do to surface this error to the
frontend / user in a friendly way.
2023-09-28 10:14:16 -04:00
Brandon Thomas fc47232e6b Update general_setup.md 2023-09-27 17:27:55 -04:00
Brandon Thomas 83dc262249 make lints and tests pass again 2023-09-26 02:13:16 -04:00
Brandon Thomas 1d3885c367 vendor in easyenv.rs (a crate I wrote) 2023-09-26 02:03:25 -04:00
Brandon Thomas 070433b416 Add watermarking capability 2023-09-22 11:49:55 -04:00
Brandon Thomas f15b89cf3d add face animation statistic to queue stats endpoint 2023-09-22 09:19:13 -04:00
Brandon Thomas 699bb6a6a7 Clion auto-optimize imports, remove dead imports, Clippy lint 2023-09-20 01:39:58 -04:00
Brandon Thomas 226f111a00 fix tests, lints 2023-09-20 01:07:26 -04:00
Brandon Thomas b7794ab48f ignore test data 2023-09-20 00:13:06 -04:00
Brandon Thomas 0bd5c9e93b ignore c sources 2023-09-20 00:11:02 -04:00
ArEnSc 5a981f55aa Merge pull request #54 from storytold/feature/General-Setup-Update
Feature/general setup update
2023-09-19 22:33:49 -04:00
978 changed files with 27141 additions and 8281 deletions
+5
View File
@@ -75,3 +75,8 @@ TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt
# Development key. Permissible to check in.
NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL
STORYTELLER_ROOT = "/home/tensor/code/storyteller" # your path here!
STORYTELLER_FRONTEND = "storyteller-frontend"
STORYTELLER_ML = "storyteller-ml"
STORYTELLER_RUST = "storyteller-rust"
+3 -2
View File
@@ -1,5 +1,6 @@
# Ignore certain code for Github language statistics
# https://github.com/github/linguist/blob/master/docs/overrides.md
old_code/trumpet-trumped.com/dictionary/cmudict-0.7b linguist-vendored
old_code/voder-vocodes-1.0/frontends/admin/node_modules linguist-vendored
windows/sqlite linguist-vendored
old_code/voder-vocodes-1.0/frontends/admin/node_modules/** linguist-vendored
test_data/html_scraping/** linguist-vendored
windows/sqlite/** linguist-vendored
+11
View File
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
+6
View File
@@ -3,6 +3,8 @@
<words>
<w>arpabet</w>
<w>backfill</w>
<w>canonicalized</w>
<w>canonicalizing</w>
<w>cashapp</w>
<w>cheermote</w>
<w>cidrs</w>
@@ -11,7 +13,9 @@
<w>dalle</w>
<w>demuxer</w>
<w>dereferencing</w>
<w>downloaders</w>
<w>downvote</w>
<w>encodec</w>
<w>fakeyou</w>
<w>ffprobe</w>
<w>greenlight</w>
@@ -22,6 +26,8 @@
<w>hparams</w>
<w>huggingface</w>
<w>lipsync</w>
<w>mochi</w>
<w>nestedness</w>
<w>pathbuf</w>
<w>replayable</w>
<w>retryably</w>
Generated
+606 -341
View File
File diff suppressed because it is too large Load Diff
+10 -3
View File
@@ -11,28 +11,32 @@ members = [
# CLI tools for operations, etc.
"crates/cli/database_backup",
"crates/cli/database_cleanup",
"crates/cli/dev_database_seed",
"crates/cli/dev_upload_media_file",
"crates/cli/kubectl_pod_cleanup",
"crates/cli/scrape_test",
# Shared libraries
"crates/lib/actix_helpers",
"crates/lib/api_clients/cloud_storage",
#"crates/lib/api_clients/fakeyou_client",
"crates/lib/api_clients/google_drive_common",
"crates/lib/api_clients/twitch_common",
"crates/lib/bootstrap",
"crates/lib/caching/memory_caching",
"crates/lib/caching/redis_caching",
"crates/lib/concurrency",
"crates/lib/cookies",
"crates/lib/crockford",
"crates/lib/datetimes",
"crates/lib/deprecated/config", # TODO(bt, 2023-02-13): Deprecate or repurpose
"crates/lib/deprecated/container_common", # TODO(bt, 2023-02-13): Pull apart and rehome pieces
"crates/lib/deprecated/http_server_common", # TODO(bt, 2023-03-20): Move useful pieces to actix_helpers
"crates/lib/envvar",
"crates/lib/easyenv", # NB: Vendored version of https://github.com/echelon/easyenv.rs that we'll improve.
"crates/lib/errors",
"crates/lib/files/archives",
"crates/lib/files/filesys",
"crates/lib/files/hashing",
"crates/lib/files/images",
"crates/lib/files/media",
"crates/lib/files/mimetypes",
"crates/lib/idempotency",
@@ -40,13 +44,16 @@ members = [
"crates/lib/mysql_queries",
"crates/lib/redis_common",
"crates/lib/server_environment",
#"crates/lib/sqlite_queries",
"crates/lib/sqlx_mysql_helpers",
"crates/lib/storyteller_root",
"crates/lib/subprocess_common",
"crates/lib/testing",
"crates/lib/tts_common",
"crates/lib/url_config",
"crates/lib/user_input_common",
"crates/lib/web_scrapers",
#"crates/lib/api_clients/fakeyou_client",
#"crates/lib/sqlite_queries",
# Programs: Desktop apps
#"crates/programs/aichatbot-sidecar",
+3
View File
@@ -39,6 +39,9 @@ deny = [
"clippy::redundant_field_names", # Lint: Duplicate names is a burden when reading: you wonder why they're dupes.
"clippy::redundant_static_lifetimes", # Lint: feels more modern to elide static lifetimes
# Rust
"unused_imports", # These are easy to automatically cull
# Possible:
# "clippy::ptr_arg",
# "clippy::too_many_lines" (note: this is configurable)
@@ -1,6 +1,14 @@
FakeYou Development Setup (bare metal)
======================================
Set your Environment .env File with the following paths, copy this in
The root path and the folders associated with the path.
This will change the base paths for development.
STORYTELLER_ROOT = "/home/tensor/code/storyteller" # change this
STORYTELLER_FRONTEND = "storyteller-frontend"
STORYTELLER_ML = "storyteller-ml"
STORYTELLER_RUST = "storyteller-rust"
This document describes how to run the FakeYou infrastructure on your development
machine's bare metal (no containers).
@@ -32,8 +40,7 @@ Mac: (Lost the list, but it should match Linux. Install Homebrew.)
Ubuntu 22.04:
```bash
sudo apt install \
jq \
sudo apt install jq \
libmysqlclient-dev \
libsqlite3-dev \
pkgconf
@@ -109,7 +116,9 @@ error (see below).
### (7) (optional) Install the SQLx CLI (if doing database development)
```bash
cargo install sqlx-cli --no-default-features --features rustls,mysql,sqlite
# NB(bt,2023-10-04): "--no-default-features" not working
# cargo install sqlx-cli --no-default-features --features rustls,mysql,sqlite
cargo install sqlx-cli --features rustls,mysql,sqlite
```
We'll be using diesel to manage the migrations, but sqlx within the app to actually perform queries.
+6 -1
View File
@@ -10,4 +10,9 @@ select count(*) from generic_inference_jobs where status = 'pending';
update generic_inference_jobs
set status = 'dead'
where status IN ('pending', 'started', 'attempt_failed');
where status IN ('pending', 'started', 'attempt_failed');
update generic_inference_jobs
set status = 'dead'
where status IN ('pending', 'started', 'attempt_failed')
and maybe_model_type IN ('sad_talker', 'so_vits_svc');
+4 -1
View File
@@ -302,7 +302,10 @@ where token IN (
'vcm_p7m9jw1krrkr',
'vcm_x7v3m9mcvten',
'vcm_6r057m7594bv',
'vcm_wkm9e42d3spm'
'vcm_wkm9e42d3spm',
'vcm_cvz78weydh57',
'vcm_7g5q89m75n1p',
'vcm_fg3175bxy7kj'
);
@@ -2,6 +2,14 @@
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- See how many jobs of each time were created in the last period
select
distinct maybe_model_type as model_type,
count(*) as created
from generic_inference_jobs
where created_at > (CURDATE() - INTERVAL 60 MINUTE)
group by maybe_model_type;
-- See how long recent jobs are taking
select
id,
@@ -15,6 +23,19 @@ and success_execution_millis IS NOT NULL
order by id desc
limit 50;
-- See who is uploading SadTalker jobs
select
maybe_creator_user_token,
users.username as maybe_creator_username,
creator_ip_address,
count(*) as attempts
from generic_inference_jobs
left outer join users
on users.token = generic_inference_jobs.maybe_creator_user_token
where maybe_model_type = 'sad_talker'
and status IN ('pending', 'started', 'complete_failure', 'attempt_failed')
group by maybe_creator_user_token, maybe_creator_username, creator_ip_address
order by attempts desc;
-- Detailed report on most recent jobs, ordered by worst performing.
-- TODO: Determine if the problem is in downloading models. Make sure the job timer doesn't include
@@ -49,7 +70,8 @@ from (
m.token = jobs.maybe_input_source_token
where
jobs.status != 'pending'
AND jobs.created_at > NOW() - INTERVAL 20 MINUTE
AND jobs.created_at > NOW() - INTERVAL 20 MINUTE
AND jobs.maybe_model_type IN ('so_vits_svc')
order by id desc
limit 200
) as t
+1 -1
View File
@@ -35,7 +35,7 @@ order by attempts desc
select *
from tts_inference_jobs
where status = 'pending'
and creator_ip_address = '186.188.28.73'
and creator_ip_address = '191.102.120.182'
limit 1;
-- Top voices in requests
@@ -2,6 +2,20 @@
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- Per-user password resets.
-- Password resets are valid until any of the following are true:
--
-- 1) database NOW() > password_rests.expires_at
-- 2) password_rests.is_redeemed == TRUE
-- 3) users.password_version > password_resets.current_password_version
--
-- When creating a new password reset, send the user an email with the `secret_key` in the URL.
-- The user will have to supply their username and/or email address, plus the secret key to
-- redeem the password reset.
--
-- Also when creating the password hash, be sure to set `expires_at` to be "NOW() + 3 hours", or
-- some other small, reasonable time frame.
--
CREATE TABLE password_resets (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
@@ -22,7 +36,7 @@ CREATE TABLE password_resets (
-- reset is no longer valid.
current_password_version INT NOT NULL DEFAULT 0,
-- Username is a lookup key; display_name allows the user to add custom case.
-- Whether the password reset has been consumed.
is_redeemed BOOLEAN NOT NULL DEFAULT false,
-- For abuse tracking.
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
drop table zs_voices;
@@ -0,0 +1,154 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- This table contains both zero shot TTS voices (speaker embeddings) and zero shot V2V voices (speaker embeddings).
-- These are the zero shot voices that are usable by our users.
CREATE TABLE zs_voices (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- NB: No idempotency token.
-- Store it in another table to prevent duplicate record creation from rapid user inputs.
-- ========== ZERO SHOT FOREIGN KEYS AND STATE==========
-- The zero shot dataset that was used to create this voice.
-- The dataset will only be accessible to the original author of the voice.
-- The original author can create multiple voices from the same dataset.
dataset_token VARCHAR(32) NOT NULL,
-- When datasets are edited, we bump their version.
-- This tells us which version of the dataset created this voice (not that we should preserve
-- record of which samples are in which version.)
-- We can surface this to the users as well.
dataset_version INT NOT NULL DEFAULT 0,
-- ========== MODEL DETAILS ==========
-- The class or category of model/algorithm this voice is intended for.
-- * 'tts' for zero shot TTS
-- * 'vc' for zero shot voice conversion
-- * 'pitch' for pitch correction models (hypothetical)
-- * (Since this isn't an enum, the list of values can be expanded.)
model_category VARCHAR(16) NOT NULL,
-- The model used for the voice:
-- * 'vall-e-x' for Vall-E-X
-- * 'ns2vc' for NaturalSpeech2 voice conversion (hypothetical)
-- * (Since this isn't an enum, the list of values can be expanded.)
model_type VARCHAR(16) NOT NULL,
-- The version of the model.
-- If we deploy new model weights for the model, we may need to regenerate
-- all of the corresponding speaker embeddings. This lets us know which voices
-- are the old version.
-- In some cases, we may need to preserve, hide, or roll back to older versions.
model_version INTEGER UNSIGNED NOT NULL DEFAULT 0,
-- What kind of features these are: spectrogram, encodec, etc.
-- Technically we shouldn't need this, as the 2-tuple (model_type, model_version) implicitly knows
-- what its features should be, but this is probably useful for our own analysis and may be easier
-- to deal with.
--
-- Example values:
-- * 'spectrogram'
-- * 'encodec'
-- * (Since this isn't an enum, the list of values can be expanded.)
encoding_type VARCHAR(16) NOT NULL,
-- ========== VOICE DETAILS ==========
-- The "title" of the voice. This can be the name and additional information as supplied by the user.
title VARCHAR(255) NOT NULL,
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- The wide varchar space is because these language tags can become cumbersome, eg "hy-Latn-IT-arevela"
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es" and "en-US" becomes "en")
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
-- TODO: misc speaker metadata
-- We'll want rich metadata for search
-- series_name VARCHAR(255) DEFAULT NULL,
-- speaker_name VARCHAR(255) DEFAULT NULL,
-- speaker_gender VARCHAR(255) DEFAULT NULL,
-- speaker_age VARCHAR(255) DEFAULT NULL,
-- speaker_voice_style VARCHAR(255) DEFAULT NULL,
-- ========== STORAGE DETAILS ==========
-- The hash for the bucket directory that contains the original upload
-- eg. /speaker_vectors/{bucket_hash}/{voice_model_version}.bin
bucket_hash VARCHAR(32) NOT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- The creator can set a desired visibility for their data.
-- This does not always apply to every upload type.
-- Additionally, some upload types may require moderator approval prior
-- to being publicly listed, and this field has no bearing on that.
-- NB: DO NOT CHANGE THE ORDER OF THE ENUM VALUES DURING SCHEMA MIGRATIONS.
creator_set_visibility ENUM(
'public',
'hidden',
'private'
) NOT NULL DEFAULT 'public',
-- The synthetic id associated with this result.
-- These ids are incremented on a per-user basis to help users
-- sequence their own work. They serve no other purpose.
maybe_creator_synthetic_id BIGINT(20) DEFAULT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
-- TODO: These are not correct. Fix these before landing / running migrations.
KEY index_model_category (model_category),
KEY index_model_type (model_type),
KEY index_model_type_and_version (model_type, model_version),
KEY index_encoding_type (encoding_type),
KEY index_ietf_primary_language_subtag (ietf_primary_language_subtag),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
drop table zs_voice_datasets;
@@ -0,0 +1,106 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- This table describes a zero shot voice in the process of being created (or later reused / edited / enhanced)
-- These are not usable voices until their vector embeddings have been created, and this table does not serve
-- the production voice list.
--
-- Multiple voices can be created from a single "dataset" as the data set is mutable over time. Users can add or
-- remove new samples to the data set at any time.
CREATE TABLE zs_voice_datasets (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- NB: No idempotency token.
-- Store it in another table to prevent duplicate record creation from rapid user inputs.
-- ========== VOICE DETAILS ==========
-- The "title" of the voice. This can be the name and additional information as supplied by the user.
-- When the voice embeddings are created, this will be copied to the produced "voice" (embeddings) record.
title VARCHAR(255) NOT NULL,
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- The wide varchar space is because these language tags can become cumbersome, eg "hy-Latn-IT-arevela"
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es" and "en-US" becomes "en")
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
-- TODO: misc speaker metadata
-- We'll want rich metadata for search
-- When the voice embeddings are created, this will be copied to the produced "voice" (embeddings) record.
-- We don't want a hard link between the dataset and the produced voice as the voice is static once
-- created (with the exception of regenerating embeddings), but the dataset my drift as the user experiments,
-- adds/removes samples, etc.
-- series_name VARCHAR(255) DEFAULT NULL,
-- speaker_name VARCHAR(255) DEFAULT NULL,
-- speaker_gender VARCHAR(255) DEFAULT NULL,
-- speaker_age VARCHAR(255) DEFAULT NULL,
-- speaker_voice_style VARCHAR(255) DEFAULT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- The creator can set a desired visibility for their data.
-- This does not always apply to every upload type.
-- Additionally, some upload types may require moderator approval prior
-- to being publicly listed, and this field has no bearing on that.
-- NB: DO NOT CHANGE THE ORDER OF THE ENUM VALUES DURING SCHEMA MIGRATIONS.
creator_set_visibility ENUM(
'public',
'hidden',
'private'
) NOT NULL DEFAULT 'public',
-- The synthetic id associated with this result.
-- These ids are incremented on a per-user basis to help users
-- sequence their own work. They serve no other purpose.
maybe_creator_synthetic_id BIGINT(20) DEFAULT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
KEY index_ietf_primary_language_subtag (ietf_primary_language_subtag),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
drop table zs_voice_dataset_samples;
@@ -0,0 +1,84 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- These are the individual files in each dataset.
-- Files can be added and removed from a dataset at any time.
CREATE TABLE zs_voice_dataset_samples (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- NB: No idempotency token.
-- Store it in another table to prevent duplicate record creation from rapid user inputs.
-- ========== ZERO SHOT FOREIGN KEYS AND STATE==========
-- The zero shot dataset that was used to create this voice.
-- The dataset will only be accessible to the original author of the voice.
-- The original author can create multiple voices from the same dataset.
dataset_token VARCHAR(32) NOT NULL,
-- Foreign key to the uploaded media file.
-- There was an option of handling uploads and file management separately, but by electing to store the dataset
-- samples in the "media_files" table, they can be reused by our other code, queries, machinery, etc.
-- Note that this requires that the "media_files" record must be an audio (not video) file (which our code will
-- enforce), and that it is given a category of "voice_zero_shot" so it isn't co-mingled with other uploads/outputs
media_file_token VARCHAR(32) NOT NULL,
-- Some data sets require raw transcripts for the audio.
-- If required, they'll live here.
maybe_raw_transcription TEXT DEFAULT NULL,
-- A way to order the data set samples
-- We don't necessarily need to reimplement file reordering.
-- order_id INT DEFAULT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
KEY fk_dataset_token (dataset_token),
KEY fk_media_file_token (media_file_token),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
drop table zs_voice_included_samples;
@@ -0,0 +1,26 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- In order to rebuild any "zs_voice", we need to know which dataset samples were included.
-- Since users can change the dataset at any time after a voice was originally created, these
-- records are generated to retain a record of which samples fed into a given voice.
-- These records will probably not be used for any product features, just as a means to study
-- poor-performing voices, perform migrations, etc.
CREATE TABLE zs_voice_included_samples (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- First member of composite effective "primary key"
-- The "zs_voice" that was created.
voice_token VARCHAR(32) NOT NULL,
-- Second member of composite effective "primary key"
-- The "zs_voice_dataset_sample" that was used.
dataset_sample_token VARCHAR(32) NOT NULL,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (voice_token, dataset_sample_token)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files DROP COLUMN maybe_public_bucket_extension;
@@ -0,0 +1,7 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files
ADD COLUMN maybe_public_bucket_extension VARCHAR(16) DEFAULT NULL
AFTER public_bucket_directory_hash;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files DROP COLUMN maybe_public_bucket_prefix;
@@ -0,0 +1,7 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files
ADD COLUMN maybe_public_bucket_prefix VARCHAR(16) DEFAULT NULL
AFTER public_bucket_directory_hash;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files DROP COLUMN origin_product_category;
@@ -0,0 +1,10 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE media_files
ADD COLUMN origin_product_category VARCHAR(16) NOT NULL DEFAULT "unknown"
AFTER origin_category;
ALTER TABLE media_files
ADD INDEX index_origin_product_category (origin_product_category);
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs DROP COLUMN frontend_failure_category;
@@ -0,0 +1,7 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs
ADD COLUMN frontend_failure_category VARCHAR(32) DEFAULT NULL
AFTER internal_debugging_failure_reason;
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE zs_voice_dataset_samples DROP COLUMN uuid_idempotency_token;
@@ -0,0 +1,10 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE zs_voice_dataset_samples
ADD COLUMN uuid_idempotency_token VARCHAR(36) NOT NULL
AFTER token;
ALTER TABLE zs_voice_dataset_samples
ADD UNIQUE INDEX unique_index_uuid_idempotency_token (uuid_idempotency_token);
@@ -0,0 +1,5 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE password_resets DROP INDEX unique_user_token_and_secret_key;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE password_resets
ADD UNIQUE INDEX unique_user_token_and_secret_key (user_token, secret_key);
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE password_resets
MODIFY ip_address_redemption VARCHAR(40) NOT NULL;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE password_resets
MODIFY ip_address_redemption VARCHAR(40) DEFAULT NULL;
@@ -0,0 +1,13 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs
MODIFY status ENUM(
'pending',
'started',
'complete_success',
'complete_failure',
'attempt_failed',
'dead'
) NOT NULL DEFAULT 'pending';
@@ -0,0 +1,16 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- Add two states to allow us to distinguish user-cancelled jobs and system-cancelled jobs.
ALTER TABLE generic_inference_jobs
MODIFY status ENUM(
'pending',
'started',
'complete_success',
'complete_failure',
'attempt_failed',
'dead',
'cancelled_by_user',
'cancelled_by_system'
) NOT NULL DEFAULT 'pending';
@@ -123,11 +123,19 @@ CREATE TABLE generic_inference_jobs (
-- ========== DEVELOPMENT AND DEBUGGING METADATA ==========
-- If true, the request gets a "debug" flag, which may do different
-- things depending on the type of work.
-- things depending on the type of work. This doesn't really have any
-- specific meaning -- it can be used to flag for anything -- but should
-- typically be used for one-off debugging and not a part of the normal
-- product surface area. Contrast this with `maybe_routing_tag`, which
-- forces the job onto a specific physical server: this might be a flag
-- deployed to handle debugging across the entire fleet.
is_debug_request BOOLEAN NOT NULL DEFAULT FALSE,
-- If set, the request gets processed by a special "tagged" worker
-- that matches this tag. The ordinary workers will ignore this work.
-- The tag is typically added via a special HTTP header when the work
-- is enqueued. In practice, this means we can canary deploy or cordon
-- off special workers to handle certain jobs.
maybe_routing_tag VARCHAR(32) DEFAULT NULL,
-- ========== JOB SYSTEM DETAILS ==========
@@ -137,9 +145,11 @@ CREATE TABLE generic_inference_jobs (
-- * Pending = job is ready to go
-- * Started = job is running
-- * Complete_Success = job is done (success)
-- * Complete_Failure = job is done (failure)
-- * Complete_Failure = job is done (permanent failure, eg. a Face Animator job without a face)
-- * Attempt_Failed = job failed but may retry.
-- * Dead = job failed permanently.
-- * Dead = job failed permanently (ie. exhausted retries)
-- * Cancelled_By_User = the user canceled their own job
-- * Cancelled_By_System = the system terminated the job (ie. load shedding, user account deletion, etc.)
--
-- Pending -> Started -> Complete_Success
-- |-> Complete_Failure
@@ -150,17 +160,41 @@ CREATE TABLE generic_inference_jobs (
'complete_success',
'complete_failure',
'attempt_failed',
'dead') NOT NULL DEFAULT 'pending',
'dead',
'cancelled_by_user',
'cancelled_by_system'
) NOT NULL DEFAULT 'pending',
-- We can track this against a "max_attempt_count"
attempt_count SMALLINT UNSIGNED NOT NULL DEFAULT 0,
-- If there is a failure, tell the user why.
-- This isn't localized or very friendly to present to the user.
failure_reason VARCHAR(512) DEFAULT NULL,
-- Optional internal-only debugging information in the case of failure.
internal_debugging_failure_reason VARCHAR(512) DEFAULT NULL,
-- An enum-like key to present the frontend with a failure class in an
-- i18n-friendly way. The javascript/frontend can use these as indices
-- into descriptive, broadly-localized error messages.
--
-- * 'face_not_detected' for images or videos that do not have a detectable
-- face (SadTalker, Wav2Lip, etc.)
--
-- * 'keep_alive_elapsed' when users walk away from their inference job and
-- the workload class expects for them to remain
--
-- * 'not_yet_implemented' error for developers during feature development
-- and prototyping. Should ideally never happen in
-- production
--
-- * 'retryable_worker_error' for generic worker errors (full filesystem,
-- etc.) that can be retried. (We don't need to
-- tell the user why the job failed.)
--
frontend_failure_category VARCHAR(32) DEFAULT NULL,
-- On success, we populate how long the job execution took in milliseconds.
-- We have this because 1) the job system timestamps are second-resolution,
-- and 2) the structure of the jobs executor may change, potentially changing
+35 -3
View File
@@ -19,12 +19,28 @@ CREATE TABLE media_files (
-- ========== FOREIGN KEY TO ORIGIN ==========
-- Where the file came from:
-- Broad category for where the file came from:
-- * 'inference' for inference output
-- * 'processed' for processed file
-- * 'upload' for direct user upload
-- * 'processed' for processed file (eg. mp3 encoding, stem splitting, etc.)
-- * 'upload' for direct user upload (from the filesystem)
-- * 'device_api' for direct user uploads recorded using Browser/Device APIs.
origin_category VARCHAR(16) NOT NULL,
-- TODO: Remove default value once records backfilled and queries updated.
-- Product area where the media file originated.
-- This is not the *model* that created the thing, this is the *product*.
-- (The underlying models can change over time.)
--
-- This value indicates what product originally created the media file. (Not the ML model or
-- user upload process.) This will let us scope media files to the product that generated them
-- and filter them out of unrelated products if necessary (eg. a user probably doesn't want
-- "Voice Designer" dataset samples in a video generation flow.)
--
-- Possible values:
-- * 'face_animator' for uploads and outputs
-- * 'unknown' for legacy records without an associated product (TODO: This should be temporary)
origin_product_category VARCHAR(16) NOT NULL DEFAULT "unknown",
-- For inference that can be tied back to a model, the type of model.
-- * 'sad_talker', which doesn't have a value for maybe_origin_model_token (!!!)
-- * (more tome come)
@@ -88,8 +104,24 @@ CREATE TABLE media_files (
-- The hash for the bucket directory that contains the original upload
-- as well as any transcodings, downsamplings, etc.
-- The bucket filename for the primary file (not including the directory path) is given by:
-- `[{maybe_public_bucket_prefix}]{public_bucket_directory_hash}[{maybe_public_bucket_extension}]`
public_bucket_directory_hash VARCHAR(32) NOT NULL,
-- An optional prefix on the bucket filename.
-- If present, this will be prepended to the beginning of the bucket filename to access the file.
-- The bucket filename for the primary file (not including the directory path) is given by:
-- `[{maybe_public_bucket_prefix}]{public_bucket_directory_hash}[{maybe_public_bucket_extension}]`
maybe_public_bucket_prefix VARCHAR(16) DEFAULT NULL,
-- An optional appended extension on the bucket filename.
-- If present, this will be appended to the end of the bucket filename to access the file.
-- To allow for flexibility, this extension typically will contain a leading period if
-- the file needs it (eg ".mp4" rather than "mp4")!
-- The bucket filename for the primary file (not including the directory path) is given by:
-- `[{maybe_public_bucket_prefix}]{public_bucket_directory_hash}[{maybe_public_bucket_extension}]`
maybe_public_bucket_extension VARCHAR(16) DEFAULT NULL,
-- NB: Removed, since this can be derived.
-- The directory this media is uploaded to will be exclusive for this file.
-- Only this given record will live in this bucket, but the directory may include
+1 -1
View File
@@ -98,7 +98,7 @@ CREATE TABLE media_uploads (
'public',
'hidden',
'private'
) NOT NULL DEFAULT 'public',
) NOT NULL DEFAULT 'public',
-- The synthetic id associated with this result.
-- These ids are incremented on a per-user basis to help users
@@ -83,9 +83,10 @@ CREATE TABLE tts_models (
-- ========== UNSTRUCTURED METADATA ==========
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- The wide varchar space is because these language tags can become cumbersome, eg "hy-Latn-IT-arevela"
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es")
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es" and "en-US" becomes "en")
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
-- The "name" of the voice model, which might be complicated.
@@ -0,0 +1,68 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- Per-user password resets.
-- Password resets are valid until any of the following are true:
--
-- 1) database NOW() > password_rests.expires_at
-- 2) password_rests.is_redeemed == TRUE
-- 3) users.password_version > password_resets.current_password_version
--
-- When creating a new password reset, send the user an email with the `secret_key` in the URL.
-- The user will have to supply their username and/or email address, plus the secret key to
-- redeem the password reset.
--
-- Also when creating the password hash, be sure to set `expires_at` to be "NOW() + 3 hours", or
-- some other small, reasonable time frame.
--
CREATE TABLE password_resets (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Password hash "primary key"
-- (ie. for the future when we have a support dashboard)
token VARCHAR(32) NOT NULL,
-- Foreign key to user
user_token VARCHAR(32) NOT NULL,
-- Secret "key" for the password reset
-- This will be shared via URL or user text input.
secret_key VARCHAR(32) NOT NULL,
-- Copied from the user record at the time of password reset issuance.
-- If the user's password version is greater than this value, then this
-- reset is no longer valid.
current_password_version INT NOT NULL DEFAULT 0,
-- Whether the password reset has been consumed.
is_redeemed BOOLEAN NOT NULL DEFAULT false,
-- For abuse tracking.
-- Wide enough for IPv4/6
ip_address_creation VARCHAR(40) NOT NULL,
ip_address_redemption VARCHAR(40) DEFAULT NULL,
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- When the password reset expires
expires_at TIMESTAMP NOT NULL,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
UNIQUE KEY (user_token, secret_key),
KEY fk_user_token (user_token),
KEY index_secret_key (secret_key),
KEY index_expires_at (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,89 @@
-- NB: This is a manually squashed view of all the CREATE and ALTER statements,
-- with comments attached to the fields for centralized documentation.
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- These are the individual files in each dataset.
-- Files can be added and removed from a dataset at any time.
CREATE TABLE zs_voice_dataset_samples (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- Idempotency token from client
-- This is so the frontend client doesn't submit duplicate uploads.
uuid_idempotency_token VARCHAR(36) NOT NULL,
-- ========== ZERO SHOT FOREIGN KEYS AND STATE==========
-- The zero shot dataset that was used to create this voice.
-- The dataset will only be accessible to the original author of the voice.
-- The original author can create multiple voices from the same dataset.
dataset_token VARCHAR(32) NOT NULL,
-- Foreign key to the uploaded media file.
-- There was an option of handling uploads and file management separately, but by electing to store the dataset
-- samples in the "media_files" table, they can be reused by our other code, queries, machinery, etc.
-- Note that this requires that the "media_files" record must be an audio (not video) file (which our code will
-- enforce), and that it is given a category of "voice_zero_shot" so it isn't co-mingled with other uploads/outputs
media_file_token VARCHAR(32) NOT NULL,
-- Some data sets require raw transcripts for the audio.
-- If required, they'll live here.
maybe_raw_transcription TEXT DEFAULT NULL,
-- A way to order the data set samples
-- We don't necessarily need to reimplement file reordering.
-- order_id INT DEFAULT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
UNIQUE KEY (uuid_idempotency_token),
KEY fk_dataset_token (dataset_token),
KEY fk_media_file_token (media_file_token),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,109 @@
-- NB: This is a manually squashed view of all the CREATE and ALTER statements,
-- with comments attached to the fields for centralized documentation.
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- This table describes a zero shot voice in the process of being created (or later reused / edited / enhanced)
-- These are not usable voices until their vector embeddings have been created, and this table does not serve
-- the production voice list.
--
-- Multiple voices can be created from a single "dataset" as the data set is mutable over time. Users can add or
-- remove new samples to the data set at any time.
CREATE TABLE zs_voice_datasets (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- NB: No idempotency token.
-- Store it in another table to prevent duplicate record creation from rapid user inputs.
-- ========== VOICE DETAILS ==========
-- The "title" of the voice. This can be the name and additional information as supplied by the user.
-- When the voice embeddings are created, this will be copied to the produced "voice" (embeddings) record.
title VARCHAR(255) NOT NULL,
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- The wide varchar space is because these language tags can become cumbersome, eg "hy-Latn-IT-arevela"
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es" and "en-US" becomes "en")
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
-- TODO: misc speaker metadata
-- We'll want rich metadata for search
-- When the voice embeddings are created, this will be copied to the produced "voice" (embeddings) record.
-- We don't want a hard link between the dataset and the produced voice as the voice is static once
-- created (with the exception of regenerating embeddings), but the dataset my drift as the user experiments,
-- adds/removes samples, etc.
-- series_name VARCHAR(255) DEFAULT NULL,
-- speaker_name VARCHAR(255) DEFAULT NULL,
-- speaker_gender VARCHAR(255) DEFAULT NULL,
-- speaker_age VARCHAR(255) DEFAULT NULL,
-- speaker_voice_style VARCHAR(255) DEFAULT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- The creator can set a desired visibility for their data.
-- This does not always apply to every upload type.
-- Additionally, some upload types may require moderator approval prior
-- to being publicly listed, and this field has no bearing on that.
-- NB: DO NOT CHANGE THE ORDER OF THE ENUM VALUES DURING SCHEMA MIGRATIONS.
creator_set_visibility ENUM(
'public',
'hidden',
'private'
) NOT NULL DEFAULT 'public',
-- The synthetic id associated with this result.
-- These ids are incremented on a per-user basis to help users
-- sequence their own work. They serve no other purpose.
maybe_creator_synthetic_id BIGINT(20) DEFAULT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
KEY index_ietf_primary_language_subtag (ietf_primary_language_subtag),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -0,0 +1,157 @@
-- NB: This is a manually squashed view of all the CREATE and ALTER statements,
-- with comments attached to the fields for centralized documentation.
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- This table contains both zero shot TTS voices (speaker embeddings) and zero shot V2V voices (speaker embeddings).
-- These are the zero shot voices that are usable by our users.
CREATE TABLE zs_voices (
-- Not used for anything except replication.
id BIGINT(20) NOT NULL AUTO_INCREMENT,
-- Effective "primary key" for joins, API, etc. (PUBLIC)
token VARCHAR(32) NOT NULL,
-- NB: No idempotency token.
-- Store it in another table to prevent duplicate record creation from rapid user inputs.
-- ========== ZERO SHOT FOREIGN KEYS AND STATE==========
-- The zero shot dataset that was used to create this voice.
-- The dataset will only be accessible to the original author of the voice.
-- The original author can create multiple voices from the same dataset.
dataset_token VARCHAR(32) NOT NULL,
-- When datasets are edited, we bump their version.
-- This tells us which version of the dataset created this voice (not that we should preserve
-- record of which samples are in which version.)
-- We can surface this to the users as well.
dataset_version INT NOT NULL DEFAULT 0,
-- ========== MODEL DETAILS ==========
-- The class or category of model/algorithm this voice is intended for.
-- * 'tts' for zero shot TTS
-- * 'vc' for zero shot voice conversion
-- * 'pitch' for pitch correction models (hypothetical)
-- * (Since this isn't an enum, the list of values can be expanded.)
model_category VARCHAR(16) NOT NULL,
-- The model used for the voice:
-- * 'vall-e-x' for Vall-E-X
-- * 'ns2vc' for NaturalSpeech2 voice conversion (hypothetical)
-- * (Since this isn't an enum, the list of values can be expanded.)
model_type VARCHAR(16) NOT NULL,
-- The version of the model.
-- If we deploy new model weights for the model, we may need to regenerate
-- all of the corresponding speaker embeddings. This lets us know which voices
-- are the old version.
-- In some cases, we may need to preserve, hide, or roll back to older versions.
model_version INTEGER UNSIGNED NOT NULL DEFAULT 0,
-- What kind of features these are: spectrogram, encodec, etc.
-- Technically we shouldn't need this, as the 2-tuple (model_type, model_version) implicitly knows
-- what its features should be, but this is probably useful for our own analysis and may be easier
-- to deal with.
--
-- Example values:
-- * 'spectrogram'
-- * 'encodec'
-- * (Since this isn't an enum, the list of values can be expanded.)
encoding_type VARCHAR(16) NOT NULL,
-- ========== VOICE DETAILS ==========
-- The "title" of the voice. This can be the name and additional information as supplied by the user.
title VARCHAR(255) NOT NULL,
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- The wide varchar space is because these language tags can become cumbersome, eg "hy-Latn-IT-arevela"
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es" and "en-US" becomes "en")
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
-- TODO: misc speaker metadata
-- We'll want rich metadata for search
-- series_name VARCHAR(255) DEFAULT NULL,
-- speaker_name VARCHAR(255) DEFAULT NULL,
-- speaker_gender VARCHAR(255) DEFAULT NULL,
-- speaker_age VARCHAR(255) DEFAULT NULL,
-- speaker_voice_style VARCHAR(255) DEFAULT NULL,
-- ========== STORAGE DETAILS ==========
-- The hash for the bucket directory that contains the original upload
-- eg. /speaker_vectors/{bucket_hash}/{voice_model_version}.bin
bucket_hash VARCHAR(32) NOT NULL,
-- ========== CREATOR DETAILS AND PREFERENCES ==========
-- Foreign key to user
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- Based on a cookie sent by the frontend.
-- We'll save this even if the user is logged in.
maybe_creator_anonymous_visitor_token VARCHAR(32) DEFAULT NULL,
-- For abuse tracking.
-- Wide enough for IPv4/6
creator_ip_address VARCHAR(40) NOT NULL,
-- The creator can set a desired visibility for their data.
-- This does not always apply to every upload type.
-- Additionally, some upload types may require moderator approval prior
-- to being publicly listed, and this field has no bearing on that.
-- NB: DO NOT CHANGE THE ORDER OF THE ENUM VALUES DURING SCHEMA MIGRATIONS.
creator_set_visibility ENUM(
'public',
'hidden',
'private'
) NOT NULL DEFAULT 'public',
-- The synthetic id associated with this result.
-- These ids are incremented on a per-user basis to help users
-- sequence their own work. They serve no other purpose.
maybe_creator_synthetic_id BIGINT(20) DEFAULT NULL,
-- ========== MODERATION DETAILS ==========
-- The last moderator that made changes last.
-- Fine details of moderator actions are kept in a separate `audit_logs` table.
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- If this is removed by a mod or the creator.
user_deleted_at TIMESTAMP NULL,
mod_deleted_at TIMESTAMP NULL,
-- ========== VECTOR CLOCK ==========
-- Incremented with every update.
version INT NOT NULL DEFAULT 0,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
-- TODO: These are not correct. Fix these before landing / running migrations.
KEY index_model_category (model_category),
KEY index_model_type (model_type),
KEY index_model_type_and_version (model_type, model_version),
KEY index_encoding_type (encoding_type),
KEY index_ietf_primary_language_subtag (ietf_primary_language_subtag),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_user_deleted_at (user_deleted_at),
KEY index_mod_deleted_at (mod_deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -3
View File
@@ -18,7 +18,7 @@ build_shared_mysql_database_library() {
# NB: For now, this is our monolithic DB that serves all of our microservices (gross)
# It's a single package so that queries can be shared (again, gross)
pushd crates/lib/mysql_queries
SQLX_OFFLINE=true cargo sqlx prepare --merged
SQLX_OFFLINE=true cargo sqlx prepare
popd
}
@@ -35,6 +35,9 @@ build_shared_sqlite_database_library() {
echo 'mysql prepare'
build_shared_mysql_database_library
echo 'sqlite prepare'
build_shared_sqlite_database_library
#echo 'sqlite prepare'
#build_shared_sqlite_database_library
echo 'done'
@@ -1,6 +1,7 @@
use crockford::crockford_entropy_lower;
use crate::public::public_path::PublicPath;
use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string;
use crockford::crockford_entropy_lower;
// TODO: Generate these from a macro.
@@ -1,7 +1,9 @@
use std::path::PathBuf;
use crockford::crockford_entropy_lower;
use crate::public::media_files::directory::MediaFileBucketDirectory;
use crate::public::public_path::PublicPath;
use crockford::crockford_entropy_lower;
use std::path::PathBuf;
const ORIGINAL_FILE_BASENAME : &str = "file.bin";
@@ -12,25 +14,43 @@ const ORIGINAL_FILE_BASENAME : &str = "file.bin";
#[derive(Clone)]
pub struct MediaFileBucketPath {
directory: MediaFileBucketDirectory,
filename: String,
full_object_path: String,
optional_prefix: Option<String>,
/// NB: Extension contains the leading period, eg. ".mp4"
optional_extension: Option<String>,
}
impl PublicPath for MediaFileBucketPath {}
impl MediaFileBucketPath {
pub fn generate_new() -> Self {
pub fn generate_new(optional_prefix: Option<&str>, optional_extension: Option<&str>) -> Self {
let entropy = crockford_entropy_lower(32);
Self::from_object_hash(&entropy)
Self::from_object_hash(&entropy, optional_prefix, optional_extension)
}
pub fn from_object_hash(hash: &str) -> Self {
pub fn from_object_hash(hash: &str, optional_prefix: Option<&str>, optional_extension: Option<&str>) -> Self {
// TODO: Path construction could be cleaner.
let directory = MediaFileBucketDirectory::from_object_hash(hash);
let full_object_path = format!("{}/{}", directory.get_directory_path_str(), ORIGINAL_FILE_BASENAME);
let filename = match (optional_prefix, optional_extension) {
(None, None) => ORIGINAL_FILE_BASENAME.to_string(),
(None, Some(ext)) => format!("{}{}", hash, ext),
(Some(pre), None) => format!("{}{}", pre, hash),
(Some(pre), Some(ext)) => format!("{}{}{}", pre, hash, ext),
};
let full_object_path = format!("{}/{}", directory.get_directory_path_str(), filename);
Self {
directory,
filename,
full_object_path,
optional_prefix: optional_prefix.map(|p| p.to_string()),
optional_extension: optional_extension.map(|e| e.to_string()),
}
}
@@ -50,52 +70,76 @@ impl MediaFileBucketPath {
&self.directory.get_object_hash()
}
pub fn get_basename() -> &'static str {
ORIGINAL_FILE_BASENAME
pub fn get_basename(&self) -> &str {
&self.filename
}
}
#[cfg(test)]
mod tests {
use crate::public::media_files::original_file::MediaFileBucketPath;
use std::path::PathBuf;
#[test]
pub fn generate_new_entropy() {
let file = MediaFileBucketPath::generate_new();
assert_eq!(file.get_object_hash().len(), 32);
assert_eq!(file.get_directory().get_object_hash().len(), 32);
use crate::public::media_files::original_file::MediaFileBucketPath;
mod with_prefix_and_extension {
use super::*;
#[test]
pub fn generate_new_entropy() {
let file = MediaFileBucketPath::generate_new(Some("pre_"), Some(".mp4"));
assert_eq!(file.get_object_hash().len(), 32);
assert_eq!(file.get_object_hash().len(), 32);
assert_eq!(file.get_directory().get_object_hash().len(), 32);
}
#[test]
pub fn get_full_object_path_str() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk", Some("pre_"), Some(".mp4"));
assert_eq!(file.get_full_object_path_str(), "/media/a/b/c/d/e/abcdefghijk/pre_abcdefghijk.mp4");
assert_eq!(file.get_basename(), "pre_abcdefghijk.mp4");
}
}
#[test]
pub fn get_full_object_path_str() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk");
assert_eq!(file.get_full_object_path_str(), "/media/a/b/c/d/e/abcdefghijk/file.bin");
}
mod without_prefix_and_extension {
use super::*;
#[test]
pub fn to_full_object_pathbuf() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk");
assert_eq!(file.to_full_object_pathbuf(), PathBuf::from("/media/a/b/c/d/e/abcdefghijk/file.bin"));
}
#[test]
pub fn generate_new_entropy() {
let file = MediaFileBucketPath::generate_new(None, None);
assert_eq!(file.get_object_hash().len(), 32);
assert_eq!(file.get_directory().get_object_hash().len(), 32);
}
#[test]
pub fn get_full_object_path_str_short_name() {
let file = MediaFileBucketPath::from_object_hash("foo");
assert_eq!(file.get_full_object_path_str(), "/media/f/o/foo/file.bin");
}
#[test]
pub fn get_full_object_path_str() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk", None, None);
assert_eq!(file.get_full_object_path_str(), "/media/a/b/c/d/e/abcdefghijk/file.bin");
}
#[test]
pub fn get_full_object_path_str_starts_with_directory() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk");
let full_path = file.get_full_object_path_str();
assert!(full_path.starts_with(file.get_directory().get_directory_path_str()))
}
#[test]
pub fn to_full_object_pathbuf() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk", None, None);
assert_eq!(file.to_full_object_pathbuf(), PathBuf::from("/media/a/b/c/d/e/abcdefghijk/file.bin"));
}
#[test]
pub fn get_object_hash() {
let hash = "abcdefghijk";
let file = MediaFileBucketPath::from_object_hash(hash);
assert_eq!(file.get_object_hash(), hash);
#[test]
pub fn get_full_object_path_str_short_name() {
let file = MediaFileBucketPath::from_object_hash("foo", None, None);
assert_eq!(file.get_full_object_path_str(), "/media/f/o/foo/file.bin");
}
#[test]
pub fn get_full_object_path_str_starts_with_directory() {
let file = MediaFileBucketPath::from_object_hash("abcdefghijk", None, None);
let full_path = file.get_full_object_path_str();
assert!(full_path.starts_with(file.get_directory().get_directory_path_str()))
}
#[test]
pub fn get_object_hash() {
let hash = "abcdefghijk";
let file = MediaFileBucketPath::from_object_hash(hash, None, None);
assert_eq!(file.get_object_hash(), hash);
}
}
}
@@ -1,6 +1,7 @@
use crockford::crockford_entropy_lower;
use crate::public::public_path::PublicPath;
use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string;
use crockford::crockford_entropy_lower;
// TODO: Generate these from a macro.
@@ -1,7 +1,9 @@
use std::path::PathBuf;
use crockford::crockford_entropy_lower;
use crate::public::media_uploads::directory::MediaUploadDirectory;
use crate::public::public_path::PublicPath;
use crockford::crockford_entropy_lower;
use std::path::PathBuf;
const ORIGINAL_FILE_BASENAME : &str = "original_upload.bin";
@@ -57,9 +59,10 @@ impl MediaUploadOriginalFilePath {
#[cfg(test)]
mod tests {
use crate::public::media_uploads::original_file::MediaUploadOriginalFilePath;
use std::path::PathBuf;
use crate::public::media_uploads::original_file::MediaUploadOriginalFilePath;
#[test]
pub fn generate_new_entropy() {
let file = MediaUploadOriginalFilePath::generate_new();
@@ -1,7 +1,9 @@
use std::path::PathBuf;
use crockford::crockford_entropy_lower;
use crate::public::public_path::PublicPath;
use crate::public::voice_conversion_results::directory::VoiceConversionResultDirectory;
use crockford::crockford_entropy_lower;
use std::path::PathBuf;
const ORIGINAL_FILE_PREFIX : &str = "fakeyou_";
const ORIGINAL_FILE_SUFFIX : &str = ".wav";
@@ -61,9 +63,10 @@ impl VoiceConversionResultOriginalFilePath {
#[cfg(test)]
mod tests {
use crate::public::voice_conversion_results::original_file::VoiceConversionResultOriginalFilePath;
use std::path::PathBuf;
use crate::public::voice_conversion_results::original_file::VoiceConversionResultOriginalFilePath;
#[test]
pub fn generate_new_entropy() {
let file = VoiceConversionResultOriginalFilePath::generate_new();
@@ -1,6 +1,7 @@
use std::path::PathBuf;
use errors::AnyhowResult;
use errors::bail;
use std::path::PathBuf;
#[deprecated(note = "this is a messy function and should be avoided")]
pub (crate) fn hash_to_bucket_path(file_hash: &str,
@@ -28,9 +29,10 @@ pub (crate) fn hash_to_bucket_path(file_hash: &str,
#[cfg(test)]
mod tests {
use crate::util::hash_to_bucket_path::hash_to_bucket_path;
use std::path::PathBuf;
use crate::util::hash_to_bucket_path::hash_to_bucket_path;
#[test]
fn test_bucket_without_root() {
assert_eq!(
@@ -1,6 +1,7 @@
use crate::util::hash_to_bucket_path::hash_to_bucket_path;
use errors::AnyhowResult;
use errors::anyhow;
use errors::AnyhowResult;
use crate::util::hash_to_bucket_path::hash_to_bucket_path;
#[deprecated(note = "this is a messy function and should be avoided")]
pub fn hash_to_bucket_path_string(file_hash: &str,
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -0,0 +1,145 @@
use std::collections::BTreeSet;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `frontend_failure_category`.
///
/// When jobs fail (permanently or transiently), we need to inform the frontend of the reason,
/// because perhaps there's something the user can do to change their input.
///
/// The previous "VARCHAR(32) failure_reason" column was a text-based message that could not be
/// localized or made user friendly. This `frontend_failure_category` exists to provide well-defined
/// failure categories to the frontend that can easily be localized and indicated consistently in
/// the UI.
///
/// Another benefit is that we'll surface all of the various types of failure and perhaps eventually
/// come to handle some in a cross-cutting way.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub enum FrontendFailureCategory {
/// When a face is not detected in the image used for animation.
/// For SadTalker (and possibly Wav2Lip)
#[serde(rename = "face_not_detected")]
FaceNotDetected,
/// The user stepped away from their device and expected the workload to finish.
/// Some workloads require that the user keep their browser open.
#[serde(rename = "keep_alive_elapsed")]
KeepAliveElapsed,
/// This is mostly for developers -- a feature isn't complete somewhere in the code.
/// Big oops if errors of this class make it to production.
#[serde(rename = "not_yet_implemented")]
NotYetImplemented,
/// Tell the user that some kind of transient error happened. They don't need to know
/// exactly what happened. We'll retry their workload in any case.
#[serde(rename = "retryable_worker_error")]
RetryableWorkerError,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(FrontendFailureCategory);
impl_mysql_enum_coders!(FrontendFailureCategory);
/// NB: Legacy API for older code.
impl FrontendFailureCategory {
pub fn to_str(&self) -> &'static str {
match self {
Self::FaceNotDetected => "face_not_detected",
Self::KeepAliveElapsed => "keep_alive_elapsed",
Self::NotYetImplemented => "not_yet_implemented",
Self::RetryableWorkerError => "retryable_worker_error",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"face_not_detected" => Ok(Self::FaceNotDetected),
"keep_alive_elapsed" => Ok(Self::KeepAliveElapsed),
"not_yet_implemented" => Ok(Self::NotYetImplemented),
"retryable_worker_error" => Ok(Self::RetryableWorkerError),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::FaceNotDetected,
Self::KeepAliveElapsed,
Self::NotYetImplemented,
Self::RetryableWorkerError,
])
}
}
#[cfg(test)]
mod tests {
use crate::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(FrontendFailureCategory::FaceNotDetected, "face_not_detected");
assert_serialization(FrontendFailureCategory::KeepAliveElapsed, "keep_alive_elapsed");
assert_serialization(FrontendFailureCategory::NotYetImplemented, "not_yet_implemented");
assert_serialization(FrontendFailureCategory::RetryableWorkerError, "retryable_worker_error");
}
#[test]
fn to_str() {
assert_eq!(FrontendFailureCategory::FaceNotDetected.to_str(), "face_not_detected");
assert_eq!(FrontendFailureCategory::KeepAliveElapsed.to_str(), "keep_alive_elapsed");
assert_eq!(FrontendFailureCategory::NotYetImplemented.to_str(), "not_yet_implemented");
assert_eq!(FrontendFailureCategory::RetryableWorkerError.to_str(), "retryable_worker_error");
}
#[test]
fn from_str() {
assert_eq!(FrontendFailureCategory::from_str("face_not_detected").unwrap(), FrontendFailureCategory::FaceNotDetected);
assert_eq!(FrontendFailureCategory::from_str("keep_alive_elapsed").unwrap(), FrontendFailureCategory::KeepAliveElapsed);
assert_eq!(FrontendFailureCategory::from_str("not_yet_implemented").unwrap(), FrontendFailureCategory::NotYetImplemented);
assert_eq!(FrontendFailureCategory::from_str("retryable_worker_error").unwrap(), FrontendFailureCategory::RetryableWorkerError);
}
#[test]
fn all_variants() {
let mut variants = FrontendFailureCategory::all_variants();
assert_eq!(variants.len(), 4);
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::FaceNotDetected));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::KeepAliveElapsed));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::NotYetImplemented));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RetryableWorkerError));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(FrontendFailureCategory::all_variants().len(), FrontendFailureCategory::iter().len());
}
#[test]
fn round_trip() {
for variant in FrontendFailureCategory::all_variants() {
assert_eq!(variant, FrontendFailureCategory::from_str(variant.to_str()).unwrap());
assert_eq!(variant, FrontendFailureCategory::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, FrontendFailureCategory::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `inference_category`.
///
/// Our "generic inference" pipeline supports a wide variety of ML models and other media.
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `maybe_input_source_token`.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `maybe_model_type`.
///
/// Our "generic inference" pipeline supports a wide variety of ML models and other media.
@@ -20,20 +19,18 @@ use strum::EnumIter;
pub enum InferenceModelType {
#[serde(rename = "rvc_v2")]
RvcV2,
// NB: sad_talker does use user-supplied models, so there is no "model token"
#[serde(rename = "sad_talker")]
SadTalker,
#[serde(rename = "so_vits_svc")]
SoVitsSvc,
// TODO: Does this need to be "legacy_tacotron2" ?
#[serde(rename = "tacotron2")]
Tacotron2,
#[serde(rename = "vits")]
Vits,
#[serde(rename = "vall_e_x")]
VallEX,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
@@ -49,6 +46,7 @@ impl InferenceModelType {
Self::SoVitsSvc => "so_vits_svc",
Self::Tacotron2 => "tacotron2",
Self::Vits => "vits",
Self::VallEX => "vall_e_x"
}
}
@@ -59,6 +57,7 @@ impl InferenceModelType {
"so_vits_svc" => Ok(Self::SoVitsSvc),
"tacotron2" => Ok(Self::Tacotron2),
"vits" => Ok(Self::Vits),
"vall_e_x" => Ok(Self::VallEX),
_ => Err(format!("invalid value: {:?}", value)),
}
}
@@ -72,6 +71,7 @@ impl InferenceModelType {
InferenceModelType::SoVitsSvc,
InferenceModelType::Tacotron2,
InferenceModelType::Vits,
InferenceModelType::VallEX
])
}
}
@@ -88,6 +88,7 @@ mod tests {
assert_serialization(InferenceModelType::SoVitsSvc, "so_vits_svc");
assert_serialization(InferenceModelType::Tacotron2, "tacotron2");
assert_serialization(InferenceModelType::Vits, "vits");
assert_serialization(InferenceModelType::VallEX, "vall_e_x");
}
#[test]
@@ -97,6 +98,7 @@ mod tests {
assert_eq!(InferenceModelType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(InferenceModelType::Tacotron2.to_str(), "tacotron2");
assert_eq!(InferenceModelType::Vits.to_str(), "vits");
assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x");
}
#[test]
@@ -106,18 +108,20 @@ mod tests {
assert_eq!(InferenceModelType::from_str("so_vits_svc").unwrap(), InferenceModelType::SoVitsSvc);
assert_eq!(InferenceModelType::from_str("tacotron2").unwrap(), InferenceModelType::Tacotron2);
assert_eq!(InferenceModelType::from_str("vits").unwrap(), InferenceModelType::Vits);
assert_eq!(InferenceModelType::from_str("vall_e_x").unwrap(), InferenceModelType::VallEX);
}
#[test]
fn all_variants() {
// Static check
let mut variants = InferenceModelType::all_variants();
assert_eq!(variants.len(), 5);
assert_eq!(variants.len(), 6);
assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2));
assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker));
assert_eq!(variants.pop_first(), Some(InferenceModelType::SoVitsSvc));
assert_eq!(variants.pop_first(), Some(InferenceModelType::Tacotron2));
assert_eq!(variants.pop_first(), Some(InferenceModelType::Vits));
assert_eq!(variants.pop_first(), Some(InferenceModelType::VallEX));
assert_eq!(variants.pop_first(), None);
// Generated check
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `on_success_result_entity_type`.
///
/// Our "generic inference" pipeline supports a wide variety of output types.
@@ -1,3 +1,4 @@
pub mod frontend_failure_category;
pub mod inference_category;
pub mod inference_input_source_token_type;
pub mod inference_model_type;
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `generic_synthetic_ids` table in `VARCHAR(32)` field `id_category`.
///
/// This lets us create synthetic increment IDs on a per-user, per-category basis.
@@ -21,6 +20,23 @@ pub enum IdCategory {
/// Results from lipsync animations (which may live in the media_files table)
#[serde(rename = "lipsync_animation")]
LipsyncAnimation,
/// Results from voice conversion (which may live in the media_files table)
/// Applies for RVC and SVC
#[serde(rename = "voice_conversion")]
VoiceConversion,
/// Results from the zero shot tts
#[serde(rename = "zs_audio_tts")]
ZeroShotTTS,
/// Zs dataset which lives in the zs_voice_datasets table
#[serde(rename = "zs_dataset")]
ZsDataset,
/// Zs voice which lives in the zs_voices table
#[serde(rename = "zs_voice")]
ZsVoice,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
@@ -33,6 +49,10 @@ impl IdCategory {
match self {
Self::MediaFile => "media_file",
Self::LipsyncAnimation => "lipsync_animation",
Self::VoiceConversion => "voice_conversion",
Self::ZsDataset => "zs_dataset",
Self::ZsVoice => "zs_voice",
Self::ZeroShotTTS => "zs_audio_tts"
}
}
@@ -40,6 +60,10 @@ impl IdCategory {
match value {
"media_file" => Ok(Self::MediaFile),
"lipsync_animation" => Ok(Self::LipsyncAnimation),
"voice_conversion" => Ok(Self::VoiceConversion),
"zs_dataset" => Ok(Self::ZsDataset),
"zs_voice" => Ok(Self::ZsVoice),
"zs_audio_tts" => Ok(Self::ZeroShotTTS),
_ => Err(format!("invalid value: {:?}", value)),
}
}
@@ -50,6 +74,10 @@ impl IdCategory {
BTreeSet::from([
Self::MediaFile,
Self::LipsyncAnimation,
Self::VoiceConversion,
Self::ZsDataset,
Self::ZsVoice,
Self::ZeroShotTTS
])
}
}
@@ -59,35 +87,73 @@ mod tests {
use crate::by_table::generic_synthetic_ids::id_category::IdCategory;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(IdCategory::MediaFile, "media_file");
assert_serialization(IdCategory::LipsyncAnimation, "lipsync_animation");
assert_serialization(IdCategory::VoiceConversion, "voice_conversion");
assert_serialization(IdCategory::ZsDataset, "zs_dataset");
assert_serialization(IdCategory::ZsVoice, "zs_voice");
}
#[test]
fn to_str() {
assert_eq!(IdCategory::MediaFile.to_str(), "media_file");
assert_eq!(IdCategory::LipsyncAnimation.to_str(), "lipsync_animation");
#[test]
fn to_str() {
assert_eq!(IdCategory::MediaFile.to_str(), "media_file");
assert_eq!(IdCategory::LipsyncAnimation.to_str(), "lipsync_animation");
assert_eq!(IdCategory::VoiceConversion.to_str(), "voice_conversion");
assert_eq!(IdCategory::ZsDataset.to_str(), "zs_dataset");
assert_eq!(IdCategory::ZsVoice.to_str(), "zs_voice");
assert_eq!(IdCategory::ZeroShotTTS.to_str(),"zs_audio_tts");
}
#[test]
fn from_str() {
assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile);
assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimation);
assert_eq!(IdCategory::from_str("voice_conversion").unwrap(), IdCategory::VoiceConversion);
assert_eq!(IdCategory::from_str("zs_dataset").unwrap(), IdCategory::ZsDataset);
assert_eq!(IdCategory::from_str("zs_voice").unwrap(), IdCategory::ZsVoice);
assert_eq!(IdCategory::from_str("zs_audio_tts").unwrap(), IdCategory::ZeroShotTTS);
}
#[test]
fn all_variants() {
// Static check
let mut variants = IdCategory::all_variants();
assert_eq!(variants.len(), 5);
assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile));
assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimation));
assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversion));
assert_eq!(variants.pop_first(), Some(IdCategory::ZsDataset));
assert_eq!(variants.pop_first(), Some(IdCategory::ZsVoice));
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotTTS));
assert_eq!(variants.pop_first(), None);
// Generated check
use strum::IntoEnumIterator;
assert_eq!(IdCategory::all_variants().len(), IdCategory::iter().len());
}
}
#[test]
fn from_str() {
assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile);
assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimation);
}
mod mechanical_checks {
use super::*;
#[test]
fn all_variants() {
// Static check
let mut variants = IdCategory::all_variants();
assert_eq!(variants.len(), 2);
assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile));
assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimation));
assert_eq!(variants.pop_first(), None);
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(IdCategory::all_variants().len(), IdCategory::iter().len());
}
// Generated check
use strum::IntoEnumIterator;
assert_eq!(IdCategory::all_variants().len(), IdCategory::iter().len());
#[test]
fn round_trip() {
for variant in IdCategory::all_variants() {
assert_eq!(variant, IdCategory::from_str(variant.to_str()).unwrap());
assert_eq!(variant, IdCategory::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, IdCategory::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -1,6 +1,6 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -10,8 +10,8 @@ use strum::EnumIter;
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum MediaFileOriginCategory {
/// ML model inference output - uploaded models or zero shot.
Inference,
@@ -19,8 +19,11 @@ pub enum MediaFileOriginCategory {
/// Processed results - (we don't have these systems yet, but eg. trim, transcode, etc).
Processed,
/// User uploaded files
/// User uploaded files (from their filesystem)
Upload,
/// User uploaded files recorded directly from their device (browser, mobile), typically using device APIs.
DeviceApi,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
@@ -34,6 +37,7 @@ impl MediaFileOriginCategory {
Self::Inference => "inference",
Self::Processed => "processed",
Self::Upload => "upload",
Self::DeviceApi => "device_api",
}
}
@@ -42,9 +46,21 @@ impl MediaFileOriginCategory {
"inference" => Ok(Self::Inference),
"processed" => Ok(Self::Processed),
"upload" => Ok(Self::Upload),
"device_api" => Ok(Self::DeviceApi),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::Inference,
Self::Processed,
Self::Upload,
Self::DeviceApi,
])
}
}
#[cfg(test)]
@@ -52,25 +68,62 @@ mod tests {
use crate::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use crate::test_helpers::assert_serialization;
#[test]
fn test_serialization() {
assert_serialization(MediaFileOriginCategory::Inference, "inference");
assert_serialization(MediaFileOriginCategory::Processed, "processed");
assert_serialization(MediaFileOriginCategory::Upload, "upload");
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(MediaFileOriginCategory::Inference, "inference");
assert_serialization(MediaFileOriginCategory::Processed, "processed");
assert_serialization(MediaFileOriginCategory::Upload, "upload");
assert_serialization(MediaFileOriginCategory::DeviceApi, "device_api");
}
#[test]
fn test_to_str() {
assert_eq!(MediaFileOriginCategory::Inference.to_str(), "inference");
assert_eq!(MediaFileOriginCategory::Processed.to_str(), "processed");
assert_eq!(MediaFileOriginCategory::Upload.to_str(), "upload");
assert_eq!(MediaFileOriginCategory::DeviceApi.to_str(), "device_api");
}
#[test]
fn test_from_str() {
assert_eq!(MediaFileOriginCategory::from_str("inference").unwrap(), MediaFileOriginCategory::Inference);
assert_eq!(MediaFileOriginCategory::from_str("processed").unwrap(), MediaFileOriginCategory::Processed);
assert_eq!(MediaFileOriginCategory::from_str("upload").unwrap(), MediaFileOriginCategory::Upload);
assert_eq!(MediaFileOriginCategory::from_str("device_api").unwrap(), MediaFileOriginCategory::DeviceApi);
assert!(MediaFileOriginCategory::from_str("foo").is_err());
}
#[test]
fn all_variants() {
let mut variants = MediaFileOriginCategory::all_variants();
assert_eq!(variants.len(), 4);
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Inference));
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Processed));
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Upload));
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::DeviceApi));
assert_eq!(variants.pop_first(), None);
}
}
#[test]
fn test_to_str() {
assert_eq!(MediaFileOriginCategory::Inference.to_str(), "inference");
assert_eq!(MediaFileOriginCategory::Processed.to_str(), "processed");
assert_eq!(MediaFileOriginCategory::Upload.to_str(), "upload");
}
mod mechanical_checks {
use super::*;
#[test]
fn test_from_str() {
assert_eq!(MediaFileOriginCategory::from_str("inference").unwrap(), MediaFileOriginCategory::Inference);
assert_eq!(MediaFileOriginCategory::from_str("processed").unwrap(), MediaFileOriginCategory::Processed);
assert_eq!(MediaFileOriginCategory::from_str("upload").unwrap(), MediaFileOriginCategory::Upload);
assert!(MediaFileOriginCategory::from_str("foo").is_err());
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(MediaFileOriginCategory::all_variants().len(), MediaFileOriginCategory::iter().len());
}
#[test]
fn round_trip() {
for variant in MediaFileOriginCategory::all_variants() {
assert_eq!(variant, MediaFileOriginCategory::from_str(variant.to_str()).unwrap());
assert_eq!(variant, MediaFileOriginCategory::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, MediaFileOriginCategory::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -10,11 +11,21 @@ use strum::EnumIter;
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum MediaFileOriginModelType {
/// RVC (v2) voice conversion models
#[serde(rename = "rvc_v2")]
RvcV2,
/// SadTalker -- v1, we may add another enum value for future versions
SadTalker,
/// so-vits-svc voice conversion models
#[serde(rename = "so_vits_svc")]
SoVitsSvc,
#[serde(rename = "vall_e_x")]
VallEX,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
@@ -25,16 +36,33 @@ impl_mysql_enum_coders!(MediaFileOriginModelType);
impl MediaFileOriginModelType {
pub fn to_str(&self) -> &'static str {
match self {
Self::RvcV2 => "rvc_v2",
Self::SadTalker => "sad_talker",
Self::SoVitsSvc => "so_vits_svc",
Self::VallEX => "vall_e_x"
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"rvc_v2" => Ok(Self::RvcV2),
"sad_talker" => Ok(Self::SadTalker),
"so_vits_svc" => Ok(Self::SoVitsSvc),
"vall_e_x" => Ok(Self::VallEX),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::RvcV2,
Self::SadTalker,
Self::SoVitsSvc,
Self::VallEX
])
}
}
#[cfg(test)]
@@ -42,19 +70,60 @@ mod tests {
use crate::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(MediaFileOriginModelType::SadTalker, "sad_talker");
}
#[test]
fn test_to_str() {
assert_eq!(MediaFileOriginModelType::SadTalker.to_str(), "sad_talker");
#[test]
fn test_to_str() {
assert_eq!(MediaFileOriginModelType::RvcV2.to_str(), "rvc_v2");
assert_eq!(MediaFileOriginModelType::SadTalker.to_str(), "sad_talker");
assert_eq!(MediaFileOriginModelType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(MediaFileOriginModelType::VallEX.to_str(), "vall_e_x");
}
#[test]
fn test_from_str() {
assert_eq!(MediaFileOriginModelType::from_str("sad_talker").unwrap(), MediaFileOriginModelType::SadTalker);
#[test]
fn test_from_str() {
assert_eq!(MediaFileOriginModelType::from_str("rvc_v2").unwrap(), MediaFileOriginModelType::RvcV2);
assert_eq!(MediaFileOriginModelType::from_str("sad_talker").unwrap(), MediaFileOriginModelType::SadTalker);
assert_eq!(MediaFileOriginModelType::from_str("so_vits_svc").unwrap(), MediaFileOriginModelType::SoVitsSvc);
assert_eq!(MediaFileOriginModelType::from_str("vall_e_x").unwrap(), MediaFileOriginModelType::VallEX);
assert!(MediaFileOriginModelType::from_str("foo").is_err());
}
#[test]
fn all_variants() {
let mut variants = MediaFileOriginModelType::all_variants();
assert_eq!(variants.len(), 4);
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::RvcV2));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SadTalker));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SoVitsSvc));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::VallEX));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(MediaFileOriginModelType::all_variants().len(), MediaFileOriginModelType::iter().len());
}
#[test]
fn round_trip() {
for variant in MediaFileOriginModelType::all_variants() {
assert_eq!(variant, MediaFileOriginModelType::from_str(variant.to_str()).unwrap());
assert_eq!(variant, MediaFileOriginModelType::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, MediaFileOriginModelType::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -0,0 +1,138 @@
use std::collections::BTreeSet;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `media_files` table in `VARCHAR(16)` field `origin_product_category`.
///
/// This value indicates what product originally created the media file. (Not the ML model or
/// user upload process.) This will let us scope media files to the product that generated them
/// and filter them out of unrelated products if necessary (eg. a user probably doesn't want
/// "Voice Designer" dataset samples in a video generation flow.)
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub enum MediaFileOriginProductCategory {
/// Media files created by (or uploaded for) the Face Animator product.
/// The underlying model could be SadTalker, Wav2Lip, or some future model
#[serde(rename = "face_animator")]
FaceAnimator,
// TODO: This should be a temporary category until we migrate the DB to remove this default value
/// Unknown which product is attached to the file (generated the file, the file was
/// uploaded on behalf of, etc.)
#[serde(rename = "unknown")]
Unknown,
/// Voice conversion (either RVC or SVC)
#[serde(rename = "voice_conversion")]
VoiceConversion,
/// Media files created by (or uploaded for) the Zero Shot voice product.
#[serde(rename = "zs_voice")]
ZeroShotVoice,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(MediaFileOriginProductCategory);
impl_mysql_enum_coders!(MediaFileOriginProductCategory);
/// NB: Legacy API for older code.
impl MediaFileOriginProductCategory {
pub fn to_str(&self) -> &'static str {
match self {
Self::FaceAnimator => "face_animator",
Self::Unknown => "unknown",
Self::VoiceConversion => "voice_conversion",
Self::ZeroShotVoice => "zs_voice",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"face_animator" => Ok(Self::FaceAnimator),
"unknown" => Ok(Self::Unknown),
"voice_conversion" => Ok(Self::VoiceConversion),
"zs_voice" => Ok(Self::ZeroShotVoice),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::FaceAnimator,
Self::Unknown,
Self::VoiceConversion,
Self::ZeroShotVoice,
])
}
}
#[cfg(test)]
mod tests {
use crate::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(MediaFileOriginProductCategory::FaceAnimator, "face_animator");
assert_serialization(MediaFileOriginProductCategory::Unknown, "unknown");
assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion");
assert_serialization(MediaFileOriginProductCategory::ZeroShotVoice, "zs_voice");
}
#[test]
fn to_str() {
assert_eq!(MediaFileOriginProductCategory::FaceAnimator.to_str(), "face_animator");
assert_eq!(MediaFileOriginProductCategory::Unknown.to_str(), "unknown");
assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion");
assert_eq!(MediaFileOriginProductCategory::ZeroShotVoice.to_str(), "zs_voice");
}
#[test]
fn from_str() {
assert_eq!(MediaFileOriginProductCategory::from_str("face_animator").unwrap(), MediaFileOriginProductCategory::FaceAnimator);
assert_eq!(MediaFileOriginProductCategory::from_str("unknown").unwrap(), MediaFileOriginProductCategory::Unknown);
assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion);
assert_eq!(MediaFileOriginProductCategory::from_str("zs_voice").unwrap(), MediaFileOriginProductCategory::ZeroShotVoice);
}
#[test]
fn all_variants() {
let mut variants = MediaFileOriginProductCategory::all_variants();
assert_eq!(variants.len(), 4);
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceAnimator));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ZeroShotVoice));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(MediaFileOriginProductCategory::all_variants().len(), MediaFileOriginProductCategory::iter().len());
}
#[test]
fn round_trip() {
for variant in MediaFileOriginProductCategory::all_variants() {
assert_eq!(variant, MediaFileOriginProductCategory::from_str(variant.to_str()).unwrap());
assert_eq!(variant, MediaFileOriginProductCategory::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, MediaFileOriginProductCategory::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,3 +1,4 @@
pub mod media_file_origin_category;
pub mod media_file_origin_model_type;
pub mod media_file_origin_product_category;
pub mod media_file_type;
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -62,8 +61,8 @@ impl TtsRenderStatus {
#[cfg(test)]
mod tests {
use crate::test_helpers::assert_serialization;
use crate::by_table::tts_render_tasks::tts_render_status::TtsRenderStatus;
use crate::test_helpers::assert_serialization;
mod serde {
use super::*;
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -5,7 +5,6 @@ use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// Used in the `voice_conversion_models` table in `VARCHAR(32)` field `model_type`.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -0,0 +1,147 @@
use std::collections::BTreeSet;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// This is used in nearly every job system as an actual MySQL ENUM value:
///
/// - tts_download_job
/// - tts_inference_job
/// - w2l_download_job
/// - w2l_inference_job
/// - generic_download_job
/// - (NOT generic_inference_job, which uses JobStatusPlus)
///
/// See the documentation on the table for usage.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, sqlx::Type)]
#[serde(rename_all = "snake_case")]
#[sqlx(rename_all = "snake_case")]
pub enum JobStatus {
Pending,
Started,
CompleteSuccess,
CompleteFailure,
AttemptFailed,
Dead,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(JobStatus);
// NB: We can derive `sqlx::Type` instead of using `impl_mysql_enum_coders`
impl JobStatus {
pub fn to_str(&self) -> &'static str {
match self {
Self::Pending => "pending",
Self::Started => "started",
Self::CompleteSuccess => "complete_success",
Self::CompleteFailure => "complete_failure",
Self::AttemptFailed => "attempt_failed",
Self::Dead => "dead",
}
}
pub fn from_str(job_status: &str) -> Result<Self, String> {
match job_status {
"pending" => Ok(Self::Pending),
"started" => Ok(Self::Started),
"complete_success" => Ok(Self::CompleteSuccess),
"complete_failure" => Ok(Self::CompleteFailure),
"attempt_failed" => Ok(Self::AttemptFailed),
"dead" => Ok(Self::Dead),
_ => Err(format!("invalid job_status: {:?}", job_status)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::Pending,
Self::Started,
Self::CompleteSuccess,
Self::CompleteFailure,
Self::AttemptFailed,
Self::Dead,
])
}
}
#[cfg(test)]
mod tests {
use crate::common::job_status::JobStatus;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(JobStatus::Pending, "pending");
assert_serialization(JobStatus::Started, "started");
assert_serialization(JobStatus::CompleteSuccess, "complete_success");
assert_serialization(JobStatus::CompleteFailure, "complete_failure");
assert_serialization(JobStatus::AttemptFailed, "attempt_failed");
assert_serialization(JobStatus::Dead, "dead");
}
#[test]
fn to_str() {
assert_eq!(JobStatus::Pending.to_str(), "pending");
assert_eq!(JobStatus::Started.to_str(), "started");
assert_eq!(JobStatus::CompleteSuccess.to_str(), "complete_success");
assert_eq!(JobStatus::CompleteFailure.to_str(), "complete_failure");
assert_eq!(JobStatus::AttemptFailed.to_str(), "attempt_failed");
assert_eq!(JobStatus::Dead.to_str(), "dead");
}
#[test]
fn from_str() {
assert_eq!(JobStatus::from_str("pending").unwrap(), JobStatus::Pending);
assert_eq!(JobStatus::from_str("started").unwrap(), JobStatus::Started);
assert_eq!(JobStatus::from_str("complete_success").unwrap(), JobStatus::CompleteSuccess);
assert_eq!(JobStatus::from_str("complete_failure").unwrap(), JobStatus::CompleteFailure);
assert_eq!(JobStatus::from_str("attempt_failed").unwrap(), JobStatus::AttemptFailed);
assert_eq!(JobStatus::from_str("dead").unwrap(), JobStatus::Dead);
}
#[test]
fn all_variants() {
let mut variants = JobStatus::all_variants();
assert_eq!(variants.len(), 6);
assert_eq!(variants.pop_first(), Some(JobStatus::Pending));
assert_eq!(variants.pop_first(), Some(JobStatus::Started));
assert_eq!(variants.pop_first(), Some(JobStatus::CompleteSuccess));
assert_eq!(variants.pop_first(), Some(JobStatus::CompleteFailure));
assert_eq!(variants.pop_first(), Some(JobStatus::AttemptFailed));
assert_eq!(variants.pop_first(), Some(JobStatus::Dead));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(JobStatus::all_variants().len(), JobStatus::iter().len());
}
#[test]
fn round_trip() {
for variant in JobStatus::all_variants() {
assert_eq!(variant, JobStatus::from_str(variant.to_str()).unwrap());
assert_eq!(variant, JobStatus::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, JobStatus::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
@@ -0,0 +1,160 @@
use std::collections::BTreeSet;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
/// This is used in newer jobs (that add additional enum states)
///
/// - generic_inference_job
/// - (no other jobs yet)
///
/// See the documentation on the table for usage.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, sqlx::Type)]
#[serde(rename_all = "snake_case")]
#[sqlx(rename_all = "snake_case")]
pub enum JobStatusPlus {
Pending,
Started,
CompleteSuccess,
CompleteFailure,
AttemptFailed,
Dead,
CancelledByUser,
CancelledBySystem,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(JobStatusPlus);
// NB: We can derive `sqlx::Type` instead of using `impl_mysql_enum_coders`
impl JobStatusPlus {
pub fn to_str(&self) -> &'static str {
match self {
Self::Pending => "pending",
Self::Started => "started",
Self::CompleteSuccess => "complete_success",
Self::CompleteFailure => "complete_failure",
Self::AttemptFailed => "attempt_failed",
Self::Dead => "dead",
Self::CancelledByUser => "cancelled_by_user",
Self::CancelledBySystem => "cancelled_by_system",
}
}
pub fn from_str(job_status: &str) -> Result<Self, String> {
match job_status {
"pending" => Ok(Self::Pending),
"started" => Ok(Self::Started),
"complete_success" => Ok(Self::CompleteSuccess),
"complete_failure" => Ok(Self::CompleteFailure),
"attempt_failed" => Ok(Self::AttemptFailed),
"dead" => Ok(Self::Dead),
"cancelled_by_user" => Ok(Self::CancelledByUser),
"cancelled_by_system" => Ok(Self::CancelledBySystem),
_ => Err(format!("invalid job_status: {:?}", job_status)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::Pending,
Self::Started,
Self::CompleteSuccess,
Self::CompleteFailure,
Self::AttemptFailed,
Self::Dead,
Self::CancelledByUser,
Self::CancelledBySystem,
])
}
}
#[cfg(test)]
mod tests {
use crate::common::job_status_plus::JobStatusPlus;
use crate::test_helpers::assert_serialization;
mod explicit_checks {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(JobStatusPlus::Pending, "pending");
assert_serialization(JobStatusPlus::Started, "started");
assert_serialization(JobStatusPlus::CompleteSuccess, "complete_success");
assert_serialization(JobStatusPlus::CompleteFailure, "complete_failure");
assert_serialization(JobStatusPlus::AttemptFailed, "attempt_failed");
assert_serialization(JobStatusPlus::Dead, "dead");
assert_serialization(JobStatusPlus::CancelledByUser, "cancelled_by_user");
assert_serialization(JobStatusPlus::CancelledBySystem, "cancelled_by_system");
}
#[test]
fn to_str() {
assert_eq!(JobStatusPlus::Pending.to_str(), "pending");
assert_eq!(JobStatusPlus::Started.to_str(), "started");
assert_eq!(JobStatusPlus::CompleteSuccess.to_str(), "complete_success");
assert_eq!(JobStatusPlus::CompleteFailure.to_str(), "complete_failure");
assert_eq!(JobStatusPlus::AttemptFailed.to_str(), "attempt_failed");
assert_eq!(JobStatusPlus::Dead.to_str(), "dead");
assert_eq!(JobStatusPlus::CancelledByUser.to_str(), "cancelled_by_user");
assert_eq!(JobStatusPlus::CancelledBySystem.to_str(), "cancelled_by_system");
}
#[test]
fn from_str() {
assert_eq!(JobStatusPlus::from_str("pending").unwrap(), JobStatusPlus::Pending);
assert_eq!(JobStatusPlus::from_str("started").unwrap(), JobStatusPlus::Started);
assert_eq!(JobStatusPlus::from_str("complete_success").unwrap(), JobStatusPlus::CompleteSuccess);
assert_eq!(JobStatusPlus::from_str("complete_failure").unwrap(), JobStatusPlus::CompleteFailure);
assert_eq!(JobStatusPlus::from_str("attempt_failed").unwrap(), JobStatusPlus::AttemptFailed);
assert_eq!(JobStatusPlus::from_str("dead").unwrap(), JobStatusPlus::Dead);
assert_eq!(JobStatusPlus::from_str("cancelled_by_user").unwrap(), JobStatusPlus::CancelledByUser);
assert_eq!(JobStatusPlus::from_str("cancelled_by_system").unwrap(), JobStatusPlus::CancelledBySystem);
}
#[test]
fn all_variants() {
let mut variants = JobStatusPlus::all_variants();
assert_eq!(variants.len(), 8);
assert_eq!(variants.pop_first(), Some(JobStatusPlus::Pending));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::Started));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::CompleteSuccess));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::CompleteFailure));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::AttemptFailed));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::Dead));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::CancelledByUser));
assert_eq!(variants.pop_first(), Some(JobStatusPlus::CancelledBySystem));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(JobStatusPlus::all_variants().len(), JobStatusPlus::iter().len());
}
#[test]
fn round_trip() {
for variant in JobStatusPlus::all_variants() {
// Test to_str(), from_str(), Display, and Debug.
assert_eq!(variant, JobStatusPlus::from_str(variant.to_str()).unwrap());
assert_eq!(variant, JobStatusPlus::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, JobStatusPlus::from_str(&format!("{:?}", variant)).unwrap());
}
}
}
}
+2
View File
@@ -1,3 +1,5 @@
pub mod job_status;
pub mod job_status_plus;
pub mod sqlite;
pub mod visibility;
pub mod vocoder_type;
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -1,6 +1,5 @@
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
@@ -83,8 +82,8 @@ impl WebContentType {
#[cfg(test)]
mod tests {
use crate::test_helpers::assert_serialization;
use crate::common::sqlite::web_content_type::WebContentType;
use crate::test_helpers::assert_serialization;
mod serde {
use super::*;
@@ -144,6 +144,7 @@ mod tests {
mod serde_serialization {
use crate::common::visibility::Visibility;
use super::CompositeType;
#[test]
@@ -166,6 +167,7 @@ mod tests {
mod serde_deserialization {
use crate::common::visibility::Visibility;
use super::CompositeType;
#[test]
+1 -1
View File
@@ -18,7 +18,7 @@ path = "src/lib.rs"
# (none)
# External
anyhow = "1.0.40"
anyhow = "1.0.75"
chrono = { version = "0.4.19", features = ["serde"] }
# Serialization
-1
View File
@@ -1 +0,0 @@
pub mod media_upload;
-2
View File
@@ -1,2 +0,0 @@
pub mod download;
pub mod inference;
+15 -7
View File
@@ -1,8 +1,20 @@
//! tokens
//!
//! The purpose of this library is to have a strongly-typed primary/foreign key system.
//! Every Database or Redis key will have a type here.
//! Well known keys will have short identifiers (eg. "user" is prefixed with "U:")
//! The purpose of this library is to provide a strongly-typed primary/foreign key system with
//! well-known identifier prefixes to aid in manual database debugging.
//!
//! 1) All table foreign keys have a strongly-typed (non-stringly typed) wrapper type,
//! eg. `MediaFileToken` for the `token` field in the `media_files` table or `UserToken` for
//! the `token` field in the `users` table.
//!
//! 2) All such keys should have a well-defined constant prefix. Though tokens should be 100%
//! opaque to the user and the code, having well-defined prefixes can greatly aid when
//! debugging systems. Every table's primary key should have a unique prefix that identifies
//! that key, eg. `comment_` for the `comments` table or `m_` for the `media_files` table.
//!
//! This library does not directly introduce MySQL dependencies, so these strongly-typed token
//! types can be used in other crates, eg. for defining HTTP APIs and returning strongly-typed
//! tokens to the user.
//!
// Never allow these
@@ -39,8 +51,4 @@ mod macros;
pub (crate) mod prefixes;
pub mod files;
pub mod jobs;
pub mod tokens;
pub mod users;
pub mod voice_conversion;
+15 -2
View File
@@ -13,6 +13,8 @@ use strum::EnumIter;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(test, derive(EnumIter, EnumCount))]
pub(crate) enum EntityType {
/// AVTs are not stored as primary keys in any table, but an index in many tables.
AnonymousVisitorTracking,
AuditLog,
Comment,
DownloadJob,
@@ -24,15 +26,20 @@ pub(crate) enum EntityType {
TtsModel,
TtsRenderTask, // NB: aichatbot / sqlite
User,
UserDeprecatedDoNotUse, // NB: Users prior to 2023-10-24 used this prefix.
VoiceConversionModel,
VoiceConversionResult,
W2lTemplate,
ZsVoice,
ZsVoiceDataset,
ZsVoiceDatasetSample,
}
impl EntityType {
pub fn prefix(self) -> &'static str {
match self {
Self::AnonymousVisitorTracking => "avt_",
Self::AuditLog => "audit_",
Self::Comment => "comment_",
Self::DownloadJob => "jdown_", // NB: Was "JGUP:"
@@ -43,21 +50,27 @@ impl EntityType {
Self::NewsStory => "news_story_",
Self::TtsModel => "TM:", // NB: Old-style prefix, do not use for future tokens.
Self::TtsRenderTask => "tts_task_",
Self::User => "U:", // NB: Old-style prefix, do not use for future tokens.
Self::User => "user_",
Self::UserDeprecatedDoNotUse => "U:", // NB: Users prior to 2023-10-24 used this prefix.
Self::VoiceConversionModel => "vcm_",
Self::VoiceConversionResult => "vcr_",
Self::W2lTemplate => "WT:", // NB: Old-style prefix, do not use for future tokens.
Self::ZsVoice => "zsv_",
Self::ZsVoiceDataset => "zsd_",
Self::ZsVoiceDatasetSample => "zss_",
}
}
}
#[cfg(test)]
mod tests {
use crate::prefixes::EntityType;
use std::collections::HashSet;
use strum::EnumCount;
use strum::IntoEnumIterator;
use crate::prefixes::EntityType;
#[test]
fn test_all_prefixes_are_unique() {
let entities = EntityType::iter()
@@ -0,0 +1,16 @@
use std::fmt::Debug;
use serde::Deserialize;
use serde::Serialize;
use crate::prefixes::EntityType;
/// A rare instance that is *not* a primary key.
/// These are generated as cookies to track users for a better logged out experience and for analytics.
/// We use these as indices into several columns (ML result types, uploads, etc.)
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)]
#[sqlx(transparent)]
pub struct AnonymousVisitorTrackingToken(pub String);
impl_string_token!(AnonymousVisitorTrackingToken);
impl_crockford_generator!(AnonymousVisitorTrackingToken, 32usize, EntityType::AnonymousVisitorTracking, CrockfordLower);

Some files were not shown because too many files have changed in this diff Show More