mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 02:21:23 +00:00
Merge remote-tracking branch 'old_a/master'
Following https://stackoverflow.com/a/14470212
This commit is contained in:
commit
7ebb3382d3
1629 files changed
+287734
No files matched your search
@@ -0,0 +1,14 @@
|
||||
*secret*sh
|
||||
*~
|
||||
.env
|
||||
.env-secrets
|
||||
.git
|
||||
.idea/
|
||||
__pycache__/
|
||||
_ignored_schema.rs
|
||||
models/Wav2Lip/python/
|
||||
models/tacotron2/python/
|
||||
production_database_secret_connect.sh
|
||||
secrets.toml
|
||||
secrets.yaml
|
||||
target/
|
||||
@@ -0,0 +1,62 @@
|
||||
DATABASE_URL=mysql://storyteller:password@localhost/storyteller
|
||||
#DATABASE_URL=mysql://root:root@localhost/storyteller
|
||||
#DATABASE_URL=mysql://root@localhost/storyteller
|
||||
|
||||
# SQLX normally requires a live database to reflect upon at build time.
|
||||
# This setting turns that on and requires a `sql-data.json` cache file instead.
|
||||
# See https://github.com/launchbadge/sqlx/tree/master/sqlx-cli#readme
|
||||
#SQLX_OFFLINE=true
|
||||
|
||||
# We can't serve HTTPS locally without self-signed certificate nonsense.
|
||||
COOKIE_SECURE=false
|
||||
COOKIE_DOMAIN=.jungle.horse
|
||||
WEBSITE_HOMEPAGE_REDIRECT=http://jungle.horse
|
||||
|
||||
# Bucket config (non-secret)
|
||||
REGION_NAME=us-east1
|
||||
|
||||
TTS_DOWNLOAD_BUCKET_NAME=dev-vocodes-private-uploads
|
||||
TTS_DOWNLOAD_BUCKET_ROOT=/user_uploaded_tts_models
|
||||
|
||||
W2L_PRIVATE_DOWNLOAD_BUCKET_NAME=dev-vocodes-private-uploads
|
||||
W2L_PUBLIC_DOWNLOAD_BUCKET_NAME=dev-vocodes-public
|
||||
|
||||
PRIVATE_BUCKET_NAME=dev-vocodes-private-uploads
|
||||
PUBLIC_BUCKET_NAME=dev-vocodes-public
|
||||
|
||||
# Bucket roots
|
||||
AUDIO_UPLOADS_BUCKET_ROOT=/user_uploaded_w2l_audio
|
||||
W2L_DOWNLOAD_BUCKET_ROOT=/user_uploaded_w2l_templates
|
||||
W2L_INFERENCE_OUTPUT_BUCKET_ROOT=/w2l_output
|
||||
|
||||
W2L_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-web/models/Wav2Lip
|
||||
W2L_INFERENCE_SCRIPT_NAME=vocodes_process_inference.py
|
||||
W2L_MODEL_FILENAME=wav2lip_gan.pth
|
||||
|
||||
#W2L_MODEL_CHECKPOINT=/home/bt/models/wav2lip/s3fd-619a316812.pth
|
||||
W2L_MODEL_CHECKPOINT=/home/bt/models/wav2lip/wav2lip_gan.pth
|
||||
W2L_END_BUMP_FILENAME=vocodes-short-end-bump.mp4
|
||||
|
||||
W2L_DOWNLOAD_SCRIPT_NAME=vocodes_process_upload.py
|
||||
|
||||
TTS_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-web/models/tts
|
||||
TTS_INFERENCE_SCRIPT_NAME=vocodes_inference.py
|
||||
|
||||
TACOTRON_ROOT_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-web/models/tts
|
||||
TACOTRON_VIRTUAL_ENV_ACTIVATION_COMMAND="source python-tacotron/bin/activate"
|
||||
TACOTRON_MODEL_CHECK_SCRIPT_NAME="vocodes_model_check_tacotron.py"
|
||||
|
||||
TALKNET_ROOT_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-web/models/tts
|
||||
TALKNET_MODEL_CHECK_SCRIPT_NAME="vocodes_model_check_talknet.py"
|
||||
|
||||
TTS_INFERENCE_SIDECAR_HOSTNAME=localhost:8000
|
||||
|
||||
#TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_universal_v5.pt # THIS SOUNDS HORRID
|
||||
#TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_v4_uberduck.pt # THIS IS TOO SMALL! 300MB vs 1.2 GB!
|
||||
TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_v4.pt
|
||||
|
||||
TTS_HIFIGAN_VOCODER_MODEL_FILENAME=hifigan_universal_g_02500000.pt
|
||||
TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt
|
||||
|
||||
# Development key. Permissible to check in.
|
||||
NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL
|
||||
@@ -0,0 +1,65 @@
|
||||
# Adapted from
|
||||
# https://github.com/actions/starter-workflows/ci/docker-publish.yml
|
||||
# If using base images, don't forget to add READ access, eg. from a package settings page like:
|
||||
# https://github.com/orgs/storytold/packages/container/docker-base-images-rust-ssl/settings/actions_access
|
||||
name: Publish Docker Container to GHCR
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
# NB: Default-branch doesn't work, despite Github's documentation.
|
||||
#- $default-branch
|
||||
- master
|
||||
env:
|
||||
IMAGE_NAME: storyteller-web
|
||||
|
||||
jobs:
|
||||
# Push image to GitHub Packages.
|
||||
# See also https://docs.docker.com/docker-hub/builds/
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push'
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
#username: ${{ github.repository_owner }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build image
|
||||
run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
|
||||
|
||||
- name: Push image to GitHub Container Registry
|
||||
run: |
|
||||
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
|
||||
|
||||
# Change all uppercase to lowercase
|
||||
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
|
||||
|
||||
# Strip git ref prefix from version
|
||||
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||
|
||||
# Strip "v" prefix from tag name
|
||||
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
|
||||
|
||||
# Use Docker `latest` tag convention
|
||||
[ "$VERSION" == "$default-branch" ] && VERSION=latest
|
||||
|
||||
echo IMAGE_ID=$IMAGE_ID
|
||||
echo VERSION=$VERSION
|
||||
|
||||
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
|
||||
docker push $IMAGE_ID:$VERSION
|
||||
|
||||
SHORT_SHA=$(echo ${GITHUB_SHA} | cut -c1-12)
|
||||
|
||||
docker tag $IMAGE_NAME $IMAGE_ID:$SHORT_SHA
|
||||
docker push $IMAGE_ID:$SHORT_SHA
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
*.swo
|
||||
*.swp
|
||||
*secret*sh
|
||||
*~
|
||||
.env
|
||||
.env-secrets
|
||||
.idea/
|
||||
__pycache__/
|
||||
_ignored_schema.rs
|
||||
models/Wav2Lip/python/
|
||||
models/tacotron2/python/
|
||||
production_database_secret_connect.sh
|
||||
production_database_secret_query.sh
|
||||
secrets.toml
|
||||
secrets.yaml
|
||||
target/
|
||||
twitch_secrets.toml
|
||||
Generated
+4937
File diff suppressed because it is too large.
Load diff
+19
@@ -0,0 +1,19 @@
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
# Shared libraries
|
||||
"crates/lib/config",
|
||||
"crates/lib/container_common",
|
||||
"crates/lib/database_queries",
|
||||
"crates/lib/http_server_common",
|
||||
"crates/lib/redis_common",
|
||||
"crates/lib/tts_common",
|
||||
"crates/lib/twitch_common",
|
||||
"crates/lib/user_input_common",
|
||||
|
||||
# Application
|
||||
"crates/service/storyteller_web",
|
||||
"crates/service/twitch_pubsub_subscriber",
|
||||
"crates/service/websocket_gateway",
|
||||
]
|
||||
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
# ==================== Python Build Base ====================
|
||||
|
||||
FROM ghcr.io/storytold/docker-base-images-nvidia-cuda-experimental:080f96bc7087 as pybuild-base
|
||||
|
||||
## Authenticating with GHCR locally:
|
||||
## https://docs.github.com/en/packages/working-with-a-github-packages-registry/migrating-to-the-container-registry-from-the-docker-registry
|
||||
## ```
|
||||
## export CR_PAT=YOUR_TOKEN
|
||||
## echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
|
||||
## ```
|
||||
#
|
||||
##FROM nvidia/cuda:10.1-devel-ubuntu18.04 as pybuild-base
|
||||
#FROM nvidia/cuda:11.3.0-devel-ubuntu20.04 as pybuild-base
|
||||
#
|
||||
## tzdata install hangs without presetting the time zone
|
||||
#ENV TZ=UTC
|
||||
#RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
#
|
||||
## NB(2021-05-30): This is the image that Tacotron 2's Dockerfile specifies.
|
||||
## I have not tried this, but it might be necessary.
|
||||
##FROM pytorch/pytorch:nightly-devel-cuda10.0-cudnn7
|
||||
##ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH}
|
||||
#
|
||||
## NB: https://github.com/NVIDIA/nvidia-docker/issues/864#issuecomment-439848887
|
||||
## NB: We do not install ffmpeg, since the version is 3.8.* series and we need 4.2.*
|
||||
##
|
||||
## NB(2021-05-30): We need to install `cython3` for building modern Tacotron 2
|
||||
## dependencies (ie. protoc) on old Ubuntu
|
||||
## RUN apt-get update \
|
||||
## && apt-get install -y \
|
||||
#RUN apt-get update
|
||||
##RUN apt-cache search python3.8
|
||||
#
|
||||
## NB: Here we install nvidia drivers
|
||||
## NB: Avoid keyboard prompt
|
||||
#RUN DEBIAN_FRONTEND=noninteractive apt-get install -y nvidia-384 --no-install-recommends
|
||||
#
|
||||
## ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers
|
||||
##RUN apt-get install -y ffmpeg
|
||||
##RUN ffmpeg -version
|
||||
##RUN sleep 100
|
||||
#
|
||||
## Notes on packages:
|
||||
## * software-properties-common - needed for `apt-add-repository`
|
||||
## * pciutils - needed for `lspci | grep -i nvidia`
|
||||
#RUN apt-get install -y \
|
||||
# build-essential \
|
||||
# curl \
|
||||
# cython3 \
|
||||
# ffmpeg \
|
||||
# g++-7 \
|
||||
# gcc-7 \
|
||||
# git \
|
||||
# htop \
|
||||
# imagemagick \
|
||||
# libc++-7-dev \
|
||||
# libffi-dev \
|
||||
# libgcc-7-dev \
|
||||
# libmagic1 \
|
||||
# libsm6 \
|
||||
# libsndfile1 \
|
||||
# libssl-dev \
|
||||
# libxext6 \
|
||||
# libxrender-dev \
|
||||
# netcat \
|
||||
# pciutils \
|
||||
# python-dev \
|
||||
# python3-pip \
|
||||
# python3.8 \
|
||||
# python3.8-dev \
|
||||
# python3.8-venv\
|
||||
# redis-tools \
|
||||
# silversearcher-ag \
|
||||
# software-properties-common \
|
||||
# sox \
|
||||
# tmux \
|
||||
# vim \
|
||||
# wget
|
||||
#
|
||||
#
|
||||
## Wav2Lip needs Python3.6
|
||||
## NB: we install python3-virtualenv as `python3.6 -m venv` won't work anymore
|
||||
#RUN add-apt-repository ppa:deadsnakes/ppa
|
||||
#RUN apt-get update
|
||||
#RUN apt-get install -y python3.6
|
||||
#RUN apt-get install -y python3-virtualenv
|
||||
#RUN apt-get install -y python3.6-venv
|
||||
#RUN apt-get install -y python3.6-dev
|
||||
##RUN apt-get install python3-virtualenv
|
||||
#
|
||||
#
|
||||
#RUN python3.6 --version
|
||||
#RUN python3.8 --version
|
||||
|
||||
# We need ffmpeg version >= 4.2 (https://superuser.com/a/579110)
|
||||
# http://ubuntuhandbook.org/index.php/2020/06/install-ffmpeg-4-3-via-ppa-ubuntu-18-04-16-04/
|
||||
|
||||
#RUN apt-get install -y software-properties-common \
|
||||
# && add-apt-repository ppa:jonathonf/ffmpeg-4 \
|
||||
# && apt-get update \
|
||||
# && apt-get install -y ffmpeg
|
||||
#
|
||||
|
||||
# The downloader needs youtube-dl as a python library
|
||||
# NB: No longer maintained: https://news.ycombinator.com/item?id=28319624
|
||||
#RUN pip3 install --upgrade youtube-dl
|
||||
|
||||
# Used by the downloader script.
|
||||
# And it looks like youtube-dl is dead...
|
||||
# Per the README, it looks like pip will always pull the latest version.
|
||||
# https://github.com/yt-dlp/yt-dlp#update
|
||||
RUN python3 -m pip install --upgrade yt-dlp
|
||||
|
||||
# ==================== Python Build Step 2: Wav2Lip Requirements ====================
|
||||
|
||||
FROM pybuild-base as pybuild-requirements
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY models/Wav2Lip ./models/Wav2Lip
|
||||
WORKDIR models/Wav2Lip
|
||||
|
||||
# NB: We need Python3.6
|
||||
RUN python3.6 -m venv python
|
||||
#RUN virtualenv -p /usr/bin/python3.6 ... wait
|
||||
RUN . python/bin/activate \
|
||||
&& pip install --upgrade pip \
|
||||
&& pip install -r requirements.txt \
|
||||
&& deactivate
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY models/tts ./models/tts
|
||||
WORKDIR models/tts
|
||||
|
||||
# NB: Not sure if we need Python3.6 for Tacotron2, but Python3.8 gave me trouble.
|
||||
# NB: Setuptools fix: https://github.com/tensorflow/tensorflow/issues/34302#issuecomment-554450289
|
||||
RUN python3.6 -m venv python
|
||||
RUN . python/bin/activate \
|
||||
&& pip install --upgrade pip setuptools \
|
||||
&& pip install -r requirements-tacotron-python36.txt \
|
||||
&& deactivate
|
||||
|
||||
# ==================== Rust Build Base ====================
|
||||
|
||||
# Custom base image
|
||||
# Make sure to add this repository so it has read acces to the base image:
|
||||
# https://github.com/orgs/storytold/packages/container/docker-base-images-rust-ssl/settings/actions_access
|
||||
FROM ghcr.io/storytold/docker-base-images-rust-ssl:latest as rust-build
|
||||
WORKDIR /tmp
|
||||
|
||||
COPY Cargo.lock .
|
||||
COPY Cargo.toml .
|
||||
COPY sqlx-data.json .
|
||||
COPY crates/ ./crates
|
||||
COPY db/ ./db
|
||||
# TODO(2022-01-16): Might not be necessary:
|
||||
# COPY _migrations/ ./_migrations
|
||||
|
||||
RUN $HOME/.cargo/bin/cargo fetch
|
||||
|
||||
# Build all the binaries.
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin storyteller-web
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin tts-download-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin w2l-download-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin tts-inference-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin w2l-inference-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin websocket-gateway
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin twitch-pubsub-subscriber
|
||||
|
||||
# Final image
|
||||
# FROM ubuntu:xenial
|
||||
FROM pybuild-requirements as final
|
||||
#RUN mkdir /storyteller
|
||||
#WORKDIR /storyteller
|
||||
WORKDIR /
|
||||
|
||||
|
||||
COPY scripts/ ./scripts
|
||||
|
||||
# See: https://github.com/opencontainers/image-spec/blob/master/annotations.md
|
||||
LABEL org.opencontainers.image.authors='bt@brand.io, echelon@gmail.com'
|
||||
LABEL org.opencontainers.image.url='https://github.com/storytold/storyteller-web'
|
||||
LABEL org.opencontainers.image.documentation='https://github.com/storytold/storyteller-web'
|
||||
LABEL org.opencontainers.image.source='https://github.com/storytold/storyteller-web'
|
||||
|
||||
# NB: Comment this out for non-debug images
|
||||
# TODO: Figure out how this is done elsewhere with just the static binaries
|
||||
# Others: `mysql-client`
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
curl \
|
||||
python3-pip \
|
||||
python3 \
|
||||
wget
|
||||
|
||||
RUN python3 --version
|
||||
#RUN python3.7 -m venv python
|
||||
#RUN . python/bin/activate \
|
||||
# && pip install --upgrade pip \
|
||||
# && pip install -r requirements.txt
|
||||
|
||||
|
||||
# TODO: Use venv to do this instead.
|
||||
RUN pip3 install gdown
|
||||
|
||||
# Copy all the binaries.
|
||||
COPY --from=rust-build /tmp/target/release/storyteller-web /
|
||||
COPY --from=rust-build /tmp/target/release/tts-download-job /
|
||||
COPY --from=rust-build /tmp/target/release/tts-inference-job /
|
||||
COPY --from=rust-build /tmp/target/release/w2l-download-job /
|
||||
COPY --from=rust-build /tmp/target/release/w2l-inference-job /
|
||||
COPY --from=rust-build /tmp/target/release/websocket-gateway /
|
||||
COPY --from=rust-build /tmp/target/release/twitch-pubsub-subscriber /
|
||||
|
||||
# SSL certs are required for crypto
|
||||
COPY --from=rust-build /etc/ssl /etc/ssl
|
||||
|
||||
# Required dynamically linked libraries
|
||||
COPY --from=rust-build /lib/x86_64-linux-gnu/libssl.* /lib/x86_64-linux-gnu/
|
||||
COPY --from=rust-build /lib/x86_64-linux-gnu/libcrypto.* /lib/x86_64-linux-gnu/
|
||||
|
||||
# Make sure all the links resolve
|
||||
RUN ldd storyteller-web
|
||||
|
||||
# Without a .env file, Rust crashes "mysteriously" (ugh)
|
||||
RUN touch .env
|
||||
RUN touch .env-secrets
|
||||
|
||||
EXPOSE 8080
|
||||
CMD LD_LIBRARY_PATH=/usr/lib /storyteller-web
|
||||
|
||||
# ===================================================================================================
|
||||
# WAV2LIP WORKER
|
||||
|
||||
# ==================== Rust Build Base ====================
|
||||
|
||||
# #FROM ubuntu:xenial as rustbuild-base
|
||||
# WORKDIR /tmp
|
||||
# RUN apt-get update \
|
||||
# && apt-get install -y \
|
||||
# build-essential \
|
||||
# curl \
|
||||
# libssl-dev \
|
||||
# libssl1.0.0 \
|
||||
# pkg-config \
|
||||
# unzip \
|
||||
# wget
|
||||
# RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
# | sh -s -- --default-toolchain stable -y
|
||||
|
||||
|
||||
|
||||
# ==================== Rust Build Binary ====================
|
||||
|
||||
# FROM rustbuild-base as rustbuild-binary
|
||||
#
|
||||
# COPY Cargo.lock .
|
||||
# COPY Cargo.toml .
|
||||
# COPY w2l_server ./w2l_server
|
||||
# COPY w2l_shared ./w2l_shared
|
||||
# COPY w2l_worker ./w2l_worker
|
||||
#
|
||||
# RUN $HOME/.cargo/bin/cargo fetch
|
||||
# RUN LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} $HOME/.cargo/bin/cargo build --release --bin wav2lip_worker
|
||||
|
||||
# ==================== Final Image ====================
|
||||
|
||||
# FROM pybuild-requirements as final
|
||||
# WORKDIR /
|
||||
#
|
||||
# COPY --from=rustbuild-binary /tmp/target/release/wav2lip_worker /
|
||||
# COPY --from=rustbuild-binary /etc/ssl /etc/ssl
|
||||
# COPY --from=rustbuild-binary /lib/x86_64-linux-gnu/libssl.* /lib/x86_64-linux-gnu/
|
||||
# COPY --from=rustbuild-binary /lib/x86_64-linux-gnu/libcrypto.* /lib/x86_64-linux-gnu/
|
||||
#
|
||||
# # Without a .env file, Rust crashes "mysteriously" (ugh)
|
||||
# RUN touch .env
|
||||
#
|
||||
# RUN ldd wav2lip_worker
|
||||
#
|
||||
# EXPOSE 8080
|
||||
# CMD LD_LIBRARY_PATH=/usr/lib /wav2lip_worker
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
storyteller-web
|
||||
===============
|
||||
|
||||
This is the main user account monolith that we'll also bake other pieces into.
|
||||
|
||||
Application overview
|
||||
--------------------
|
||||
|
||||
* storyteller_web
|
||||
* `storyteller-web` - HTTP + database monolith for FakeYou
|
||||
* `tts-download-job` - Async download of models
|
||||
* `tts-inference-job` - Async TTS inference
|
||||
* `w2l-download-job` - Async download of videos and images
|
||||
* `w2l-inference-job` - Async W2L inference
|
||||
* obs_gateway
|
||||
* `obs-gateway-server` - websocket for hosting OBS, twitch pieces (move!)
|
||||
* `twitch-pubsub-job` - Subscribes to Twitch PubSub
|
||||
* `twitch-chat-job` (*TODO*) - Subscribes to Twitch chat
|
||||
* `reddit-chat-job` (*TODO*) - Subscribes to Reddit RPAN chat
|
||||
* social
|
||||
* `discord-chat-job` (*TODO*) - Subscribes to Reddit RPAN chat
|
||||
* `twitter-feed-job` (*TODO*) - Subscribes to Reddit RPAN chat
|
||||
|
||||
Schema and API notes
|
||||
--------------------
|
||||
|
||||
* [Redis Schema Notes README](_docs/redis_schema.md)
|
||||
|
||||
Local development
|
||||
-----------------
|
||||
|
||||
[Local development setup README](_docs/local_development_setup.md)
|
||||
|
||||
Production and Deployment
|
||||
-------------------------
|
||||
|
||||
[Production builds and deployment README](_docs/production_builds_and_deployment.md)
|
||||
|
||||
Development notes
|
||||
-----------------
|
||||
|
||||
[Development notes README](_docs/development_notes.md)
|
||||
|
||||
Dump a MySQL report
|
||||
-------------------
|
||||
|
||||
```
|
||||
mysql -u storyteller \
|
||||
-pPasswordHere \
|
||||
-h IP_HERE \
|
||||
-P 3306 \
|
||||
-D storyteller \
|
||||
-B \
|
||||
-e "select * from voice_clone_requests;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > voice_clone_report.csv
|
||||
```
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
* Revise this README to be more useful.
|
||||
|
||||
Notes / TODOs:
|
||||
|
||||
* Examples for good Actix+Sqlx Tests:
|
||||
https://stackoverflow.com/questions/65370752/how-do-i-create-an-actix-web-server-that-accepts-both-sqlx-database-pools-and-tr
|
||||
|
||||
* Actix/sqlx runtime compat:
|
||||
https://github.com/launchbadge/sqlx/issues/1117#issuecomment-801237734
|
||||
|
||||
* Redis caching
|
||||
|
||||
* Jobs for analytics queries
|
||||
|
||||
* Pull jobs into own repo
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
database schema
|
||||
================
|
||||
|
||||
Twitch Model
|
||||
------------
|
||||
|
||||
- `twitch_user_id`
|
||||
Though numeric, this should always be a string per
|
||||
[https://discuss.dev.twitch.tv/t/bug-v5-api-returns--id-as-string-for-featured-channels/10310]
|
||||
and
|
||||
[https://discuss.dev.twitch.tv/t/type-of-user-id-in-api-responses/10205]
|
||||
|
||||
- `twitch_channel_id`
|
||||
This is the same as `twitch_user_id`. They're exactly 1:1. Prefer to
|
||||
use 'user_id' terminology.
|
||||
|
||||
- `twitch_username`
|
||||
Between 4 and 25 characters.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
development notes
|
||||
=================
|
||||
|
||||
Actix notes
|
||||
-----------
|
||||
|
||||
json request
|
||||
```
|
||||
async fn handler(request: web::Json<Mytype>) -> impl Responder { "whatever" }
|
||||
```
|
||||
|
||||
form-multipart request
|
||||
```
|
||||
async fn handler(request: web::Form<Mytype>) -> impl Responder { "whatever" }
|
||||
```
|
||||
|
||||
route parameters
|
||||
```
|
||||
#[get("/{name}")]
|
||||
async fn hello(name: web::Path<String>) -> impl Responder { format!("Hi {}", name) }
|
||||
```
|
||||
@@ -0,0 +1,207 @@
|
||||
dev setup
|
||||
=========
|
||||
|
||||
[Back to main README](../README.md)
|
||||
|
||||
### Debugging and Fixing CUDA/PyTorch
|
||||
|
||||
See this spreadsheet for previous battles with version incompatibility:
|
||||
https://docs.google.com/spreadsheets/d/1BEdLmwOzo3r83-iJn9sj6co1VT92t3lIeJ-lNH25bdQ/edit#gid=0
|
||||
|
||||
Ubuntu might upgrade the driver by accident, and it might need reinstallation. Who knows.
|
||||
This stuff is a nightmare.
|
||||
|
||||
### Database Setup
|
||||
|
||||
Install the following libraries, and see the notes further below about MySQL on Ubuntu 20.04.
|
||||
|
||||
```
|
||||
mysql-server
|
||||
imagemagick
|
||||
```
|
||||
|
||||
To manage the database and perform migrations, install the Rust tools diesel and sqlx.
|
||||
|
||||
We'll be using diesel to manage the migrations, but sqlx within the app to actually perform queries.
|
||||
Diesel is an ORM, which is dumb, so we use sqlx as at-compile-time typesafe SQL.
|
||||
|
||||
```
|
||||
sudo apt-get install libmysqlclient-dev
|
||||
cargo install sqlx-cli --no-default-features --features mysql [2022-01-16: is this needed?]
|
||||
```
|
||||
|
||||
To install a more modern version of Diesel (unreleased) that
|
||||
supports the "migrations_dir" toml config option:
|
||||
|
||||
```
|
||||
cargo install diesel_cli \
|
||||
--git https://github.com/diesel-rs/diesel.git \
|
||||
--rev a213fe232a122f35a812b0ce0269708a1845a4c9 \
|
||||
--no-default-features \
|
||||
--features mysql
|
||||
```
|
||||
|
||||
#### Sqlx Error on Linux when Performing Schema Migrations
|
||||
|
||||
You might get this error message during migration,
|
||||
|
||||
```
|
||||
Encountered unknown type for Mysql: enum
|
||||
thread 'main' panicked at 'internal error: entered unreachable code: Mysql only supports a closed set of types.
|
||||
If you ever see this error message please open an issue at https://github.com/diesel-rs/diesel containing a dump of your schema definition.', diesel_cli/src/print_schema.rs:310:17
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
```
|
||||
|
||||
I haven't found the cause (it doesn't happen on Mac), but the migrations appear to work regardless of the error message.
|
||||
|
||||
#### Linux database notes
|
||||
|
||||
If MySql in local dev can't be connected to, reset the accounts:
|
||||
|
||||
https://linuxconfig.org/how-to-reset-root-mysql-mariadb-password-on-ubuntu-20-04-focal-fossa-linux
|
||||
|
||||
#### Fixing dev MySql on Ubuntu 20.04
|
||||
|
||||
For some reason, the MySql default install on 20.04 gave me a bunch of trouble.
|
||||
|
||||
In retrospect, I _think_ this is because 'root@localhost' requires sudo to access, but if this
|
||||
gives any trouble in the future, here's how I got around it (two full hours of distraction!)
|
||||
|
||||
```
|
||||
sudo apt-get install mysql-server
|
||||
|
||||
# But for some reason the default password doesn't work and diesel/sqlx can't connect?
|
||||
|
||||
# Kill everything
|
||||
|
||||
sudo apt purge mysql-server mysql-client mysql-common
|
||||
sudo apt autoremove
|
||||
sudo mv -iv /var/lib/mysql /var/tmp/mysql-backup
|
||||
sudo rm -rf /var/lib/mysql*
|
||||
|
||||
sudo /usr/bin/mysql_secure_installation
|
||||
|
||||
# still no work...
|
||||
|
||||
sudo systemctl stop mysql.service
|
||||
|
||||
# ugh, it wasn't chowned or created (both states observed in different installs)…
|
||||
sudo mkdir -p /var/run/mysqld
|
||||
sudo chown mysql:mysql /var/run/mysqld
|
||||
|
||||
sudo mysqld_safe --skip-grant-tables --skip-networking &
|
||||
|
||||
mysql -u root
|
||||
|
||||
flush privileges;
|
||||
USE mysql;
|
||||
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
|
||||
|
||||
sudo killall -u mysql
|
||||
sudo systemctl restart mysql.service
|
||||
|
||||
# now it works
|
||||
sudo mysql -u root -p
|
||||
|
||||
# but now I have to use "sudo" !?!?
|
||||
|
||||
use mysql;
|
||||
|
||||
CREATE USER 'storyteller'@'localhost' IDENTIFIED BY 'password';
|
||||
GRANT ALL PRIVILEGES ON storyteller.* TO 'storyteller'@'localhost';
|
||||
```
|
||||
|
||||
### Install Diesel (migrations only)
|
||||
|
||||
We use Diesel to manage migrations, but we don't use it in server code.
|
||||
Actual server code uses SQLx. To install the CLI tool, run the following:
|
||||
|
||||
```
|
||||
cargo install diesel_cli
|
||||
```
|
||||
|
||||
Mac [has issues](https://github.com/diesel-rs/diesel/issues/2605) and requires a few dependencies:
|
||||
|
||||
```
|
||||
brew install libpq
|
||||
```
|
||||
|
||||
### Database migrations
|
||||
|
||||
To reset the entire database (drop, migrate), run:
|
||||
|
||||
```
|
||||
diesel database reset
|
||||
```
|
||||
|
||||
To migrate at the current step and beyond:
|
||||
|
||||
```
|
||||
diesel migration run
|
||||
```
|
||||
|
||||
To undo migrations at the current step:
|
||||
|
||||
```
|
||||
diesel migration redo
|
||||
```
|
||||
|
||||
### Server Query Codegen
|
||||
|
||||
We use SQLx instead of Diesel in the production server. It's typesafe
|
||||
SQL instead of an ORM like Diesel.
|
||||
|
||||
SQLx connects to a database to derive type information, but obviously
|
||||
cannot do this for builds in CI. In order to cache the types, we build
|
||||
and check in a cache file (necessary for builds):
|
||||
|
||||
```
|
||||
SQLX_OFFLINE=true cargo sqlx prepare
|
||||
```
|
||||
|
||||
Now that we have multiple binaries, it's required to include all the queries in the main
|
||||
binary so we can generate the cached queries as a single target. That's then executed
|
||||
with:
|
||||
|
||||
```
|
||||
SQLX_OFFLINE=true cargo sqlx prepare -- --bin storyteller-web
|
||||
```
|
||||
|
||||
### Setting Up a Local Nginx Proxy
|
||||
|
||||
Set up a local nginx to proxy to the frontend and backend so cookie issues aren't annoying
|
||||
|
||||
Configure Nginx per the checked in Nginx configs (and instructions) in `localdev/nginx-http-config`.
|
||||
|
||||
```
|
||||
|
||||
And in /etc/hosts,
|
||||
|
||||
```
|
||||
127.0.0.1 jungle.horse
|
||||
127.0.0.1 api.jungle.horse
|
||||
|
||||
```
|
||||
|
||||
### Python 3.6 on Apple M1 Mac
|
||||
|
||||
Python3.6 isn't supported on Apple silicon, and it's not in homebrew. It can be installed with
|
||||
[nix using Rosetta](https://stackoverflow.com/a/65980989):
|
||||
|
||||
Download: https://nixos.org/download.html#nix-quick-install
|
||||
|
||||
```
|
||||
nix run nixpkgs.python36 -c python
|
||||
```
|
||||
|
||||
Install venv:
|
||||
|
||||
```
|
||||
nix run nixpkgs.python36 -c python -m venv python
|
||||
```
|
||||
|
||||
Install other packages on Mac that aren't used in venv:
|
||||
|
||||
```
|
||||
python3 -m pip install --user requests gdown youtube_dl
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
production builds and deployment
|
||||
================================
|
||||
|
||||
### Github Docker builds
|
||||
|
||||
The repository needs to be given read access to the base docker image:
|
||||
|
||||
https://github.com/orgs/storytold/packages/container/docker-base-images-rust-ssl/settings
|
||||
|
||||
These instructions assume running on GCP.
|
||||
|
||||
### Database migrations
|
||||
|
||||
1. Set `DATABASE_URL` in `.env` to the production secrets (DO NOT COMMIT!)
|
||||
2. Run `diesel migration run`
|
||||
|
||||
### Setting up public buckets without list permission
|
||||
|
||||
Public buckets that deny the `list` action should use the following Role:
|
||||
|
||||
`roles/storage.legacyObjectReader`
|
||||
|
||||
See:
|
||||
|
||||
* https://stackoverflow.com/a/56354633
|
||||
* https://cloud.google.com/storage/docs/access-control/making-data-public#buckets
|
||||
|
||||
### Generating Bucket Access Key and Secret Key
|
||||
|
||||
https://cloud.telestream.net/tutorials/how-to-setting-up-google-cloud-storage/
|
||||
|
||||
1. Go to the GCS page
|
||||
2. Click "settings"
|
||||
3. Click "interoperability" tab
|
||||
4. (enable interoperable access if not already set)
|
||||
5. Click "create new key"
|
||||
@@ -0,0 +1,27 @@
|
||||
redis schema
|
||||
============
|
||||
|
||||
Database 0: TTS / RateLimiter
|
||||
-----------------------------
|
||||
|
||||
TODO: Document rate limiter
|
||||
|
||||
Public statistics on usage displayed on the website:
|
||||
|
||||
* `ttsUseCount:{model_token}`: INCR, GET
|
||||
* `w2lUseCount:{template_token}`: INCR, GET
|
||||
|
||||
Temporary job progress reports to the user:
|
||||
|
||||
These are written as a single string, such as "downloading model", "uploading model",
|
||||
"generating preview", "executing", etc.
|
||||
|
||||
* `ttsDownloadExtraStatus:{inference_job_token}`: SETEX, GET
|
||||
* `ttsInferenceExtraStatus:{inference_job_token}`: SETEX, GET
|
||||
* `w2lDownloadExtraStatus:{inference_job_token}`: SETEX, GET
|
||||
* `w2lInferenceExtraStatus:{inference_job_token}`: SETEX, GET
|
||||
|
||||
Database 1: Obs / Twitch
|
||||
------------------------
|
||||
|
||||
* WIP
|
||||
Whitespace-only changes.
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
drop table user_roles;
|
||||
drop table user_sessions;
|
||||
drop table users;
|
||||
@@ -0,0 +1,235 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE users (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Visible "primary key"
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Username is a lookup key; display_name allows the user to add custom case.
|
||||
username VARCHAR(20) NOT NULL,
|
||||
display_name VARCHAR(20) NOT NULL,
|
||||
|
||||
email_address VARCHAR(255) NOT NULL,
|
||||
email_confirmed BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- The role assigned to the user confers permissions.
|
||||
user_role_slug VARCHAR(16) NOT NULL,
|
||||
|
||||
-- ========== CREDENTIALS ==========
|
||||
|
||||
-- Bcrypt password hash. Granted, there are newer methods:
|
||||
-- https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
|
||||
-- Passwords may be a max of 64 characters per BCrypt.
|
||||
password_hash BINARY(60) NOT NULL,
|
||||
|
||||
-- Incremented with every update to the password.
|
||||
password_version INT NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== ABUSE TRACKING ==========
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_login VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- ========== DISPLAY / PROFILE ==========
|
||||
|
||||
-- Gravatar image hashes are precomputed.
|
||||
email_gravatar_hash CHAR(32) NOT NULL,
|
||||
|
||||
-- The profile of the user in markdown (user editable).
|
||||
profile_markdown TEXT NOT NULL,
|
||||
|
||||
-- Generated HTML (not user-editable).
|
||||
profile_rendered_html TEXT NOT NULL,
|
||||
|
||||
-- An uploaded avatar. Public hash in our bucket.
|
||||
-- avatar_public_bucket_hash CHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== SOCIAL MEDIA ==========
|
||||
|
||||
-- Social media usernames
|
||||
-- These are not confirmed. We'll need to build an OAuth system to handle that.
|
||||
discord_username VARCHAR(36) DEFAULT NULL,
|
||||
twitter_username VARCHAR(36) DEFAULT NULL,
|
||||
twitch_username VARCHAR(36) DEFAULT NULL,
|
||||
patreon_username VARCHAR(36) DEFAULT NULL,
|
||||
github_username VARCHAR(36) DEFAULT NULL,
|
||||
cashapp_username VARCHAR(36) DEFAULT NULL,
|
||||
website_url VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== USER PREFERENCES ==========
|
||||
|
||||
-- If the user doesn't want to use gravatar and doesn't have an uploaded avatar.
|
||||
disable_gravatar BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
-- Visibility preference used at TTS inference time (which can be changed on the result itself).
|
||||
-- Moderators will still see them.
|
||||
preferred_tts_result_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
-- Visibility preference used at TTS inference time (which can be changed on the result itself).
|
||||
-- Moderators will still see them.
|
||||
preferred_w2l_result_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- Auto play preferences
|
||||
-- Tri-state because we want to potentially change the default behavior.
|
||||
auto_play_audio_preference BOOLEAN DEFAULT NULL,
|
||||
auto_play_video_preference BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- Favorite TTS voice to use by default
|
||||
-- maybe_preferred_tts_model_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- Favorite W2L model to use by default
|
||||
-- maybe_preferred_w2l_template_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- Settings
|
||||
-- DO NOT REORDER.
|
||||
-- dark_mode_preference ENUM(
|
||||
-- 'light-mode',
|
||||
-- 'dark-mode',
|
||||
-- 'use-clock'
|
||||
-- ) NOT NULL DEFAULT 'light-mode',
|
||||
|
||||
-- ========== STATS ==========
|
||||
|
||||
-- For tracking stats.
|
||||
-- The "cached" values are updated by a background job.
|
||||
-- cached_tts_rendered_counter INT(10) NOT NULL DEFAULT 0,
|
||||
-- cached_w2l_rendered_counter INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- Different than deleted.
|
||||
-- Users still show up, but can't do anything.
|
||||
is_banned BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- If a moderator has comments.
|
||||
maybe_mod_comments VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The last moderator that made changes.
|
||||
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- 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,
|
||||
|
||||
-- If the user is deleted, we set this.
|
||||
-- This is different than banned. These users won't show up at all.
|
||||
user_deleted_at TIMESTAMP NULL,
|
||||
mod_deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (username),
|
||||
UNIQUE KEY (email_address),
|
||||
KEY fk_user_role_slug (user_role_slug)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE user_roles (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key"
|
||||
slug CHAR(16) NOT NULL,
|
||||
|
||||
name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- Usage
|
||||
can_use_tts BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_use_w2l BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_own_tts_results BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_own_w2l_results BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_own_account BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Contribution
|
||||
can_upload_tts_models BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_upload_w2l_templates BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_own_tts_models BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_own_w2l_templates BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Moderation
|
||||
can_approve_w2l_templates BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- Edit includes "lock_from_use" and "lock_from_modification"
|
||||
can_edit_other_users_profiles BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_edit_other_users_tts_models BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_edit_other_users_w2l_templates BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_other_users_tts_models BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_other_users_tts_results BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_other_users_w2l_templates BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_other_users_w2l_results BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_ban_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_delete_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Incremented with every update.
|
||||
version INT NOT NULL DEFAULT 0,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (slug)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE user_sessions (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Session entropy
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Foreign key to user
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Track each session's creation IP.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Session termination time.
|
||||
-- This must be set by the server code, or the session is invalid
|
||||
expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- deletion = session termination
|
||||
-- Typically these are destroyed by users, but if in the future we allow mods to
|
||||
-- delete them, it doesn't really matter who did the deletion: sessions are not
|
||||
-- designed to be recoverable.
|
||||
deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_user_token (user_token),
|
||||
KEY index_ip_address_creation (ip_address_creation)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
# noinspection SqlNoDataSourceInspectionForFile
|
||||
# noinspection SqlResolveForFile
|
||||
|
||||
drop table tts_model_upload_jobs;
|
||||
drop table w2l_template_upload_jobs;
|
||||
@@ -0,0 +1,231 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: See the "squashed" copy of this for better documentation
|
||||
-- and the current state of the table.
|
||||
|
||||
-- TTS MODELS
|
||||
CREATE TABLE tts_model_upload_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UPLOAD DETAILS ==========
|
||||
|
||||
-- The name of the voice
|
||||
-- The "name" of the voice model, which might be complicated.
|
||||
-- If maybe_subject_token (etc.) is set, then it's authoritative instead.
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- NB: THIS ENUM IS OUT OF DATE!
|
||||
-- Check the squashed sql file as an updated reference!
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes'
|
||||
) NOT NULL DEFAULT 'not-set',
|
||||
|
||||
-- Can be linked to a well-known voice
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we need to download the file from Google Drive.
|
||||
download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- NB: DO NOT SORT!
|
||||
-- download_url_type ENUM(
|
||||
-- 'google-drive',
|
||||
-- 'web'
|
||||
-- ) NOT NULL DEFAULT 'web',
|
||||
|
||||
-- ========== CREATOR DETAILS AND PREFERENCES ==========
|
||||
|
||||
-- Foreign key to user
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
-- WAV2LIP TEMPLATES
|
||||
CREATE TABLE w2l_template_upload_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UPLOAD DETAILS ==========
|
||||
|
||||
-- The title of the template
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
template_type ENUM(
|
||||
'unknown',
|
||||
'video',
|
||||
'image'
|
||||
) NOT NULL DEFAULT 'unknown',
|
||||
|
||||
-- Can be linked to a well-known subject
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we need to download the file from Google Drive.
|
||||
download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- NB: DO NOT SORT!
|
||||
-- download_url_type ENUM(
|
||||
-- 'google-drive',
|
||||
-- 'web'
|
||||
-- ) NOT NULL DEFAULT 'web',
|
||||
|
||||
-- ========== CREATOR DETAILS AND PREFERENCES ==========
|
||||
|
||||
-- Foreign key to user
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
# noinspection SqlNoDataSourceInspectionForFile
|
||||
# noinspection SqlResolveForFile
|
||||
|
||||
drop table tts_models;
|
||||
drop table w2l_templates;
|
||||
@@ -0,0 +1,328 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: See the "squashed" copy of this for better documentation
|
||||
-- and the current state of the table.
|
||||
|
||||
CREATE TABLE tts_models (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- NB: THIS ENUM IS OUT OF DATE!
|
||||
-- Check the squashed sql file as an updated reference!
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes'
|
||||
) NOT NULL DEFAULT 'not-set',
|
||||
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- How text should be handled.
|
||||
text_preprocessing_algorithm ENUM(
|
||||
'basic',
|
||||
'arpabet'
|
||||
) NOT NULL DEFAULT 'basic',
|
||||
|
||||
-- NB: ADDED BY ALTER
|
||||
-- maybe_default_pretrained_vocoder VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- Optional Pointer to a newer version of the voice
|
||||
-- If there's a newer version, we can disable this one.
|
||||
-- maybe_updated_model_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- We can set as a combination of ['username' + 'voice-name']
|
||||
-- There can be public aliases for voices, eg. a voice's default model.
|
||||
-- A user can change this.
|
||||
-- As such, these should not be foreign keys.
|
||||
-- updatable_slug VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Can be linked to a well-known voice
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UNSTRUCTURED METADATA ==========
|
||||
|
||||
-- The "name" of the voice model, which might be complicated.
|
||||
-- If maybe_subject_token (etc.) is set, then it's authoritative instead.
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- The description of the model in markdown.
|
||||
description_markdown TEXT NOT NULL,
|
||||
|
||||
-- Generated HTML (not user-editable).
|
||||
description_rendered_html TEXT NOT NULL,
|
||||
|
||||
-- eg. Bill Clinton, Batman, or Goku.
|
||||
voice_name VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. Sean Schemmel
|
||||
actor_name VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. if the voice is "happy" or a singer "a-capella", etc.
|
||||
characteristic VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. if you train the model more than once.
|
||||
version_string VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== IMMUTABLE PROVENANCE AND METADATA ==========
|
||||
|
||||
-- Where the file was originally downloaded (if it was downloaded)
|
||||
original_download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- The filename that was used at upload time (if available)
|
||||
original_filename VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- File characteristics
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address_creation VARCHAR(40) NOT NULL,
|
||||
creator_ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- The pytorch model
|
||||
-- For now, this will be a hash of the file contents.
|
||||
-- NB: NOT UNIQUE! We can allow duplicate uploads.
|
||||
private_bucket_hash CHAR(64) NOT NULL,
|
||||
-- The "full url" version of the path
|
||||
private_bucket_object_name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- ========== RATING AND RANKING ==========
|
||||
|
||||
-- Calculated average, on a scale of 0-100
|
||||
-- Null with zero ratings.
|
||||
-- calculated_average_score INT(3) DEFAULT NULL,
|
||||
|
||||
-- Other metrics
|
||||
-- calculated_total_ratings_submitted_count INT(10) NOT NULL DEFAULT 0,
|
||||
-- calculated_total_uses_count BIGINT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- Mods have to approve of tts models for them to show up in a public index.
|
||||
-- Models can be used by the author (or other parties that know the URL) before
|
||||
-- they're approved, but unapproved models won't show up in public indices.
|
||||
-- This is independent of other visibility controls (is_mod_disabled, deleted_at,
|
||||
-- and creator_set_visibility)
|
||||
is_public_listing_approved BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- Extremely popular models may be locked from deletion or modification by users.
|
||||
is_locked_from_user_modification BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- In this case, a moderator disables it from being used for inference.
|
||||
-- This also disables it for the creator.
|
||||
-- Unlike deletion, it remains "visible" to those that have access.
|
||||
is_locked_from_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- If a moderator has comments.
|
||||
maybe_mod_comments VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The last moderator that made changes.
|
||||
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- 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,
|
||||
|
||||
-- If this is removed by a mod.
|
||||
-- It completely disappears from the system.
|
||||
user_deleted_at TIMESTAMP NULL,
|
||||
mod_deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
|
||||
KEY index_creator_ip_address_creation (creator_ip_address_creation),
|
||||
KEY index_creator_ip_address_last_update (creator_ip_address_last_update),
|
||||
KEY index_creator_set_visibility (creator_set_visibility),
|
||||
KEY index_private_bucket_hash (private_bucket_hash),
|
||||
KEY index_is_public_listing_approved (is_public_listing_approved),
|
||||
KEY index_is_locked_from_user_modification (is_locked_from_user_modification),
|
||||
KEY index_is_locked_from_use (is_locked_from_use)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE w2l_templates (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
template_type ENUM(
|
||||
'not-set',
|
||||
'image',
|
||||
'video'
|
||||
) NOT NULL DEFAULT 'not-set',
|
||||
|
||||
-- Optional Pointer to a newer version of the template
|
||||
-- If there's a newer version, we can disable this one.
|
||||
-- maybe_updated_template_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- A combination of ['username' + 'template-name']
|
||||
-- There can be public aliases for voices, eg. a voice's default model.
|
||||
-- A user can change this.
|
||||
-- As such, these should not be foreign keys.
|
||||
-- updatable_slug VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Can be linked to a well-known voice
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UNSTRUCTURED METADATA ==========
|
||||
|
||||
-- The title of the template.
|
||||
title CHAR(255) NOT NULL,
|
||||
|
||||
-- The description of the template in markdown.
|
||||
description_markdown TEXT NOT NULL,
|
||||
|
||||
-- Generated HTML (not user-editable).
|
||||
description_rendered_html TEXT NOT NULL,
|
||||
|
||||
-- ========== IMMUTABLE PROVENANCE AND METADATA ==========
|
||||
|
||||
-- Where the file was originally downloaded (if it was downloaded)
|
||||
original_download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- The filename that was used at upload time (if available)
|
||||
original_filename CHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Dimensions and other characteristics
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
mime_type VARCHAR(32) NOT NULL DEFAULT '',
|
||||
frame_width INT(10) NOT NULL DEFAULT 0,
|
||||
frame_height INT(10) NOT NULL DEFAULT 0,
|
||||
frame_count INT(10) NOT NULL DEFAULT 0,
|
||||
fps FLOAT NOT NULL DEFAULT 0.0,
|
||||
duration_millis INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address_creation VARCHAR(40) NOT NULL,
|
||||
creator_ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- The hash of the original source image/video
|
||||
private_bucket_hash CHAR(64) NOT NULL,
|
||||
|
||||
-- The "full path" version of the path. Contains the hash.
|
||||
private_bucket_object_name VARCHAR(255) NOT NULL,
|
||||
-- The "full path" of the cached faces object. Contains the hash.
|
||||
private_bucket_cached_faces_object_name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- The "full url" of the preview image and/or video. Contains the hash.
|
||||
maybe_public_bucket_preview_image_object_name VARCHAR(255) DEFAULT NULL,
|
||||
maybe_public_bucket_preview_video_object_name VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== RATING AND RANKING ==========
|
||||
|
||||
-- Calculated average, on a scale of 0-100
|
||||
-- Null with zero ratings.
|
||||
-- calculated_average_score INT(3) DEFAULT NULL,
|
||||
|
||||
-- Other metrics
|
||||
-- calculated_total_ratings_submitted_count INT(10) NOT NULL DEFAULT 0,
|
||||
-- calculated_total_uses_count BIGINT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- Mods have to approve of w2l templates for them to show up in a public index.
|
||||
-- Templates can be used by the author (or other parties that know the URL) before
|
||||
-- they're approved, but unapproved templates won't show up in public indices.
|
||||
-- This is independent of other visibility controls (is_mod_disabled, deleted_at,
|
||||
-- and creator_set_visibility)
|
||||
is_public_listing_approved BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- Extremely popular models may be locked from deletion or modification by users.
|
||||
is_locked_from_user_modification BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- In this case, a moderator disables it from being used for inference.
|
||||
-- This also disables it for the creator.
|
||||
-- Unlike deletion, it remains "visible" to those that have access.
|
||||
is_locked_from_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- If a moderator has comments.
|
||||
maybe_mod_comments VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The last moderator that made changes.
|
||||
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- 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,
|
||||
|
||||
-- If this is removed by a mod.
|
||||
-- It shows up nowhere if deleted.
|
||||
user_deleted_at TIMESTAMP NULL,
|
||||
mod_deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
|
||||
KEY index_template_type (template_type),
|
||||
KEY index_creator_ip_address_creation (creator_ip_address_creation),
|
||||
KEY index_creator_ip_address_last_update (creator_ip_address_last_update),
|
||||
KEY index_creator_set_visibility (creator_set_visibility),
|
||||
KEY index_private_bucket_hash (private_bucket_hash),
|
||||
KEY index_is_public_listing_approved (is_public_listing_approved),
|
||||
KEY index_is_locked_from_user_modification (is_locked_from_user_modification),
|
||||
KEY index_is_locked_from_use (is_locked_from_use)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
# noinspection SqlResolveForFile
|
||||
# noinspection SqlNoDataSourceInspectionForFile
|
||||
|
||||
drop table tts_inference_jobs;
|
||||
drop table w2l_inference_jobs;
|
||||
@@ -0,0 +1,229 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: See the "squashed" copy of this for better documentation
|
||||
-- and the current state of the table.
|
||||
|
||||
CREATE TABLE tts_inference_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS ==========
|
||||
|
||||
-- The model to use.
|
||||
-- This also determines which architecture we're using.
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- NB: ADDED BY ALTER
|
||||
-- maybe_override_pretrained_vocoder VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- The raw, unprocessed user input.
|
||||
raw_inference_text TEXT NOT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- Foreign key to user
|
||||
-- If no user is logged in, this is null.
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE w2l_inference_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS : FACE TEMPLATE ==========
|
||||
|
||||
-- The W2L template to use
|
||||
-- Can be an image or video.
|
||||
-- This is null if we're using a custom uploaded image.
|
||||
maybe_w2l_template_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we're using a custom uploaded image, this will be present.
|
||||
-- NOTE: This may never be supported.
|
||||
maybe_public_image_bucket_location VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS : AUDIO SOURCE ==========
|
||||
|
||||
-- If we're using TTS results, this will be present
|
||||
maybe_tts_inference_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we're using custom uploaded audio, this will be present.
|
||||
maybe_public_audio_bucket_hash VARCHAR(64) DEFAULT NULL,
|
||||
maybe_public_audio_bucket_location VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The filename that was used at upload time (if available)
|
||||
maybe_original_audio_filename CHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Where the audio file was originally downloaded (if it was downloaded)
|
||||
maybe_original_audio_download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
maybe_audio_mime_type VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS AND PREFERENCES ==========
|
||||
|
||||
-- Foreign key to user
|
||||
-- If no user is logged in, this is null.
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- Flags to disable branding
|
||||
disable_end_bump BOOL NOT NULL DEFAULT false,
|
||||
disable_watermark BOOL NOT NULL DEFAULT false,
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_maybe_w2l_template_token (maybe_w2l_template_token),
|
||||
KEY fk_maybe_tts_inference_result_token (maybe_tts_inference_result_token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
# noinspection SqlResolveForFile
|
||||
# noinspection SqlNoDataSourceInspectionForFile
|
||||
|
||||
drop table tts_results;
|
||||
drop table w2l_results;
|
||||
@@ -0,0 +1,184 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: See the "squashed" copy of this for better documentation
|
||||
-- and the current state of the table.
|
||||
|
||||
CREATE TABLE tts_results (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS ==========
|
||||
|
||||
-- The TTS model that was used
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- NB: ADDED BY ALTER
|
||||
-- maybe_pretrained_vocoder_used VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- The original raw, unprocessed user input.
|
||||
raw_inference_text TEXT NOT NULL,
|
||||
|
||||
-- SHA2 hash of the text [SHA2 = CHAR(64), SHA1 = CHAR(40), MD5 = CHAR(32)]
|
||||
raw_inference_text_hash_sha2 CHAR(64) NOT NULL,
|
||||
|
||||
-- First pass at text normalization.
|
||||
-- eg. 14th -> fourteenth, etc.
|
||||
normalized_inference_text TEXT NOT NULL,
|
||||
|
||||
-- If the model uses arpabet, we'll save the arpabet we used.
|
||||
maybe_arpabet_text TEXT DEFAULT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
-- If the user wasn't logged in, this is null
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
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,
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- Where the wav, spectrogram, and etc. are located.
|
||||
public_bucket_wav_audio_path VARCHAR(255) NOT NULL,
|
||||
public_bucket_spectrogram_path VARCHAR(255) NOT NULL,
|
||||
|
||||
-- ========== METADATA ==========
|
||||
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
duration_millis INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- The last moderator that made changes.
|
||||
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,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY fk_maybe_creator_anonymous_visitor_token (maybe_creator_anonymous_visitor_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;
|
||||
|
||||
CREATE TABLE w2l_results (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS ==========
|
||||
|
||||
-- The w2l template that was used (if set)
|
||||
maybe_w2l_template_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The inference result, if we're using them.
|
||||
maybe_tts_inference_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
-- If the user wasn't logged in, this is null
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
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,
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- Where the wav, spectrogram, and etc. are located.
|
||||
public_bucket_video_path VARCHAR(255) NOT NULL,
|
||||
|
||||
-- ========== METADATA ==========
|
||||
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
mime_type VARCHAR(32) NOT NULL DEFAULT '',
|
||||
frame_width INT(10) NOT NULL DEFAULT 0,
|
||||
frame_height INT(10) NOT NULL DEFAULT 0,
|
||||
duration_millis INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- The last moderator that made changes.
|
||||
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,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY fk_maybe_creator_anonymous_visitor_token (maybe_creator_anonymous_visitor_token),
|
||||
KEY fk_maybe_w2l_template_token (maybe_w2l_template_token),
|
||||
KEY fk_maybe_tts_inference_result_token (maybe_tts_inference_result_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,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
drop table badges;
|
||||
drop table user_badges;
|
||||
@@ -0,0 +1,42 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Badges are rewards for loyalty
|
||||
CREATE TABLE badges (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key"
|
||||
slug VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Description
|
||||
title VARCHAR(255) NOT NULL,
|
||||
description VARCHAR(512) NOT NULL,
|
||||
image_url VARCHAR(512) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (slug)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
-- Join table
|
||||
CREATE TABLE user_badges (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
badge_slug VARCHAR(32) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
KEY fk_user_token (user_token),
|
||||
KEY fk_badge_slug (badge_slug)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,4 @@
|
||||
# noinspection SqlResolveForFile
|
||||
# noinspection SqlNoDataSourceInspectionForFile
|
||||
|
||||
drop table firehose_entries;
|
||||
@@ -0,0 +1,37 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE firehose_entries (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Visible "primary key"
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The type of the event
|
||||
event_type VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The target user
|
||||
maybe_target_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The target "entity", which varies by event type.
|
||||
-- eg. a model token or template token
|
||||
maybe_target_entity_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If something was created, this might be the token (if we know it)
|
||||
-- eg. an inference job's token
|
||||
maybe_created_entity_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_maybe_target_user_token (maybe_target_user_token),
|
||||
KEY fk_maybe_target_entity_token (maybe_target_entity_token),
|
||||
KEY fk_maybe_created_entity_token (maybe_created_entity_token),
|
||||
KEY index_event_type (event_type)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
drop table ip_address_bans;
|
||||
@@ -0,0 +1,37 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE ip_address_bans (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- The IP address to ban
|
||||
ip_address VARCHAR(40) NOT NULL,
|
||||
|
||||
-- Maybe the target user.
|
||||
maybe_target_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- Mod who created or last edited the ban.
|
||||
mod_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Optional notes about the ban.
|
||||
mod_notes TEXT NOT NULL,
|
||||
|
||||
-- Moderator can set an expire time (optional).
|
||||
-- If not set, the ban is indefinite
|
||||
expires_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- If deleted, the ban is removed.
|
||||
deleted_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (ip_address),
|
||||
KEY fk_mod_user_token (mod_user_token),
|
||||
KEY fk_maybe_target_user_token (maybe_target_user_token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
drop table moderator_audit_log_entries;
|
||||
@@ -0,0 +1,38 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE moderator_audit_log_entries (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Visible "primary key"
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The type of the event (ban, delete, etc.)
|
||||
event_type VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The target user
|
||||
maybe_target_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The target "entity", which varies by event type.
|
||||
-- eg. a model token or template token
|
||||
maybe_target_entity_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If an IP was banned, we record it here.
|
||||
maybe_target_ip_address VARCHAR(40) DEFAULT NULL,
|
||||
|
||||
-- Optional mod-specified notes.
|
||||
optional_notes TEXT DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_maybe_target_user_token (maybe_target_user_token),
|
||||
KEY fk_maybe_target_entity_token (maybe_target_entity_token),
|
||||
KEY index_event_type (event_type)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
drop table tts_result_synthetic_ids;
|
||||
drop table w2l_result_synthetic_ids;
|
||||
@@ -0,0 +1,47 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- It gets unwieldy to show results without a numeric sequence.
|
||||
-- We create a synthetic sequence for each user to make revisiting results easier.
|
||||
CREATE TABLE tts_result_synthetic_ids (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The next result id.
|
||||
-- After we use an id, we increment this counter.
|
||||
next_id BIGINT(20) NOT NULL DEFAULT 0,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (user_token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
-- It gets unwieldy to show results without a numeric sequence.
|
||||
-- We create a synthetic sequence for each user to make revisiting results easier.
|
||||
CREATE TABLE w2l_result_synthetic_ids (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The next result id.
|
||||
-- After we use an id, we increment this counter.
|
||||
next_id BIGINT(20) NOT NULL DEFAULT 0,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (user_token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN maybe_default_pretrained_vocoder;
|
||||
|
||||
ALTER TABLE tts_inference_jobs
|
||||
DROP COLUMN maybe_override_pretrained_vocoder;
|
||||
|
||||
ALTER TABLE tts_results
|
||||
DROP COLUMN maybe_pretrained_vocoder_used;
|
||||
@@ -0,0 +1,21 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- TODO/FIXME: I originally created this with the wrong directory month.
|
||||
-- I'll have to repair the migrations table.
|
||||
-- version: 20210925010101 | run_on: 2021-08-25 03:01:15 (development)
|
||||
-- UPDATE __diesel_schema_migrations SET version=20210825010101 WHERE version=20210925010101 LIMIT 1;
|
||||
-- NB: Fixed in production on 2022-01-06
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN maybe_default_pretrained_vocoder VARCHAR(64) DEFAULT NULL
|
||||
AFTER text_preprocessing_algorithm;
|
||||
|
||||
ALTER TABLE tts_inference_jobs
|
||||
ADD COLUMN maybe_override_pretrained_vocoder VARCHAR(64) DEFAULT NULL
|
||||
AFTER model_token;
|
||||
|
||||
ALTER TABLE tts_results
|
||||
ADD COLUMN maybe_pretrained_vocoder_used VARCHAR(64) DEFAULT NULL
|
||||
AFTER model_token;
|
||||
@@ -0,0 +1 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
@@ -0,0 +1,23 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Add talknet to the tts_model_type.
|
||||
|
||||
ALTER TABLE tts_models
|
||||
MODIFY COLUMN tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes',
|
||||
'talknet'
|
||||
) NOT NULL DEFAULT 'not-set';
|
||||
|
||||
ALTER TABLE tts_model_upload_jobs
|
||||
MODIFY COLUMN tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes',
|
||||
'talknet'
|
||||
) NOT NULL DEFAULT 'not-set';
|
||||
@@ -0,0 +1,15 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN private_bucket_object_is_archive;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN has_self_contained_vocoder;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN has_self_contained_duration_model;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN has_self_contained_pitch_model;
|
||||
@@ -0,0 +1,19 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN private_bucket_object_is_archive BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER private_bucket_object_name;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN has_self_contained_vocoder BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER tts_model_type;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN has_self_contained_duration_model BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER has_self_contained_vocoder;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN has_self_contained_pitch_model BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER has_self_contained_duration_model;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE model_categories;
|
||||
DROP TABLE tts_category_assignments;
|
||||
DROP TABLE w2l_category_assignments;
|
||||
@@ -0,0 +1,174 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE model_categories (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Visible "primary key"
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token
|
||||
-- This is so the frontend client doesn't submit duplicate requests.
|
||||
-- Only used on create.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== MODEL TYPE ==========
|
||||
|
||||
model_type ENUM(
|
||||
'not_set',
|
||||
'tts',
|
||||
'w2l'
|
||||
) NOT NULL DEFAULT 'not_set',
|
||||
|
||||
-- ========== CATEGORY TOPOLOGY ==========
|
||||
|
||||
-- Optional foreign key link to super category.
|
||||
-- If absent, this is a top-level category or top-level super category.
|
||||
maybe_super_category_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If this category can be applied directly to models.
|
||||
can_directly_have_models BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- If this category can have subcategories.
|
||||
can_have_subcategories BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- If only mods are allowed to tag (or untag) models with this.
|
||||
can_only_mods_apply BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- ========== CATEGORY NAME ==========
|
||||
|
||||
-- The name of the category, which might be complicated.
|
||||
name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- The name displayed in the dropdown (if it should be different), otherwise NULL.
|
||||
-- eg. "Gender" (name) and "By Gender" (dropdown name)
|
||||
maybe_dropdown_name VARCHAR(20) DEFAULT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the category.
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address_creation VARCHAR(40) NOT NULL,
|
||||
-- Technically we don't allow editing, but just in case.
|
||||
creator_ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- Mods have to approve of categories. They remain hidden and unusable until approved.
|
||||
is_mod_approved BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- If a moderator has comments.
|
||||
maybe_mod_comments VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The last moderator that made changes.
|
||||
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- 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,
|
||||
|
||||
-- If the category is deleted and shouldn't be displayed.
|
||||
-- Only mods can delete categories.
|
||||
deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_maybe_super_category_token (maybe_super_category_token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY index_model_type (model_type),
|
||||
KEY index_can_directly_have_models (can_directly_have_models),
|
||||
KEY index_can_have_subcategories (can_have_subcategories),
|
||||
KEY index_is_mod_approved (is_mod_approved)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
-- Join table assigning models to zero or more categories.
|
||||
CREATE TABLE tts_category_assignments (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
category_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== USER DETAILS ==========
|
||||
|
||||
-- The person that created the assignment.
|
||||
-- This can be the model owner or a moderator.
|
||||
category_addition_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The person that removed the assignment.
|
||||
-- This can be the model owner or a moderator.
|
||||
category_removal_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- THIS CAN BE A MODERATOR FOR SIMPLICITY.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- ========== TIMESTAMPS ==========
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (model_token, category_token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_category_token (category_token),
|
||||
KEY index_deleted_at (deleted_at)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
-- Join table assigning models to zero or more categories.
|
||||
CREATE TABLE w2l_category_assignments (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
category_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== USER DETAILS ==========
|
||||
|
||||
-- The person that created the assignment.
|
||||
-- This can be the model owner or a moderator.
|
||||
category_addition_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The person that removed the assignment.
|
||||
-- This can be the model owner or a moderator.
|
||||
category_removal_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- THIS CAN BE A MODERATOR FOR SIMPLICITY.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- ========== TIMESTAMPS ==========
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (model_token, category_token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_category_token (category_token),
|
||||
KEY index_deleted_at (deleted_at)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_oauth_tokens;
|
||||
@@ -0,0 +1,264 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- **NOTE ABOUT DESIGN**:
|
||||
-- This table contains _many_ OAuth tokens for any single user. (many users : many tokens)
|
||||
-- An entire history of tokens is kept in the table.
|
||||
-- Apart from "deleted_at", etc., these records should largely be IMMUTABLE.
|
||||
|
||||
CREATE TABLE twitch_oauth_tokens(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Minted on first request and copied on each refresh.
|
||||
-- This allows us to group access tokens all the way back up the
|
||||
-- refresh chain.
|
||||
oauth_refresh_grouping_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== STORYTELLER/FAKEYOU USER ==========
|
||||
|
||||
-- Foreign key to user (Storyteller/FakeYou user)
|
||||
-- If no user is associated (anonymous Twitch user), then this is null.
|
||||
maybe_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== TWITCH USER ==========
|
||||
|
||||
-- The user ID / channel ID are the same
|
||||
-- https://discuss.dev.twitch.tv/t/what-is-the-difference-between-the-stream--id-and-channel--id/4423
|
||||
-- Several suggest this should be a string and not an integer
|
||||
-- https://discuss.dev.twitch.tv/t/type-of-user-id-in-api-responses/10205
|
||||
-- Yep, strings
|
||||
-- https://discuss.dev.twitch.tv/t/bug-v5-api-returns--id-as-string-for-featured-channels/10310
|
||||
twitch_user_id VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Twitch usernames are between 4 and 25 characters.
|
||||
-- This is returned in the oauth flow
|
||||
twitch_username VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Twitch username, but lowercase for lookup.
|
||||
twitch_username_lowercase VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== OAUTH TOKEN DETAILS ==========
|
||||
|
||||
-- The ever important OAuth access token.
|
||||
access_token VARCHAR(128) NOT NULL,
|
||||
|
||||
-- If we can refresh the token, this is the thing to use.
|
||||
maybe_refresh_token VARCHAR(128) DEFAULT NULL,
|
||||
|
||||
-- Should be "bearer". Included in the OAuth redemption.
|
||||
token_type VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- When the token expires from time of first grant.
|
||||
-- (We don't update this field.)
|
||||
-- Null if it does not expire or we were not informed
|
||||
expires_in_seconds INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- Number of times this token has been refreshed
|
||||
-- The original token creation will be "0", and each
|
||||
-- subsequent time will bump by one. Mostly for debugging.
|
||||
refresh_count INT(10) UNSIGNED DEFAULT 0,
|
||||
|
||||
-- ======================================================
|
||||
-- ==================== OAUTH SCOPES ====================
|
||||
-- ======================================================
|
||||
|
||||
-- TODO: Probably could have stored this in a bitfield. Ugh.
|
||||
|
||||
-- "analytics:read:extensions"
|
||||
-- "View analytics data for the Twitch Extensions owned by the authenticated account."
|
||||
has_analytics_read_extensions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- scope: "analytics:read:games"
|
||||
-- "View analytics data for the games owned by the authenticated account."
|
||||
has_analytics_read_games BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "bits:read"
|
||||
-- "View Bits information for a channel."
|
||||
has_bits_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:edit:commercial"
|
||||
-- "Run commercials on a channel."
|
||||
has_channel_edit_commercial BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:broadcast"
|
||||
-- "Manage a channel's broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
||||
has_channel_manage_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:extensions"
|
||||
-- "Manage a channel's Extension configuration, including activating Extensions."
|
||||
has_channel_manage_extensions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:polls"
|
||||
-- "Manage a channel's polls."
|
||||
has_channel_manage_polls BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:predictions"
|
||||
-- "Manage of channel's Channel Points Predictions"
|
||||
has_channel_manage_predictions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:redemptions"
|
||||
-- "Manage Channel Points custom rewards and their redemptions on a channel."
|
||||
has_channel_manage_redemptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:schedule"
|
||||
-- "Manage a channel's stream schedule."
|
||||
has_channel_manage_schedule BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:videos"
|
||||
-- "Manage a channel's videos, including deleting videos."
|
||||
has_channel_manage_videos BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:moderate"
|
||||
-- "Perform moderation actions in a channel. The user requesting the scope must be a moderator in the channel."
|
||||
has_channel_moderate BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:editors"
|
||||
-- "View a list of users with the editor role for a channel."
|
||||
has_channel_read_editors BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:goals"
|
||||
-- "View Creator Goals for a channel."
|
||||
has_channel_read_goals BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:hype_train"
|
||||
-- "View Hype Train information for a channel."
|
||||
has_channel_read_hype_train BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:polls"
|
||||
-- "View a channel's polls."
|
||||
has_channel_read_polls BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:predictions"
|
||||
-- "View a channel's Channel Points Predictions."
|
||||
has_channel_read_predictions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:redemptions"
|
||||
-- "View Channel Points custom rewards and their redemptions on a channel."
|
||||
-- eg. PubSub subscribe to `channel-points-channel-v1.<channel_id>` (channel points spends)
|
||||
has_channel_read_redemptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:stream_key"
|
||||
-- "View an authorized user's stream key."
|
||||
has_channel_read_stream_key BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:subscriptions"
|
||||
-- "View a list of all subscribers to a channel and check if a user is subscribed to a channel."
|
||||
-- eg. Enumerate list of subscribers for a channel
|
||||
-- eg. PubSub subscribe to `channel-subscribe-events-v1.<channel ID>` (subscribe, resubscribe, gift)
|
||||
has_channel_read_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel_subscriptions"
|
||||
-- "\\[DEPRECATED\\] Read all subscribers to your channel."
|
||||
has_channel_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "chat:edit"
|
||||
-- "Send live stream chat and rooms messages."
|
||||
has_chat_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "chat:read"
|
||||
-- "View live stream chat and rooms messages."
|
||||
has_chat_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "clips:edit"
|
||||
-- "Manage Clips for a channel."
|
||||
has_clips_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "moderation:read"
|
||||
-- "View a channel's moderation data including Moderators, Bans, Timeouts, and Automod settings."
|
||||
has_moderation_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "moderator:manage:automod"
|
||||
-- "Manage messages held for review by AutoMod in channels where you are a moderator."
|
||||
has_moderator_manage_auto_mod BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit"
|
||||
-- "Manage a user object."
|
||||
has_user_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit:broadcast"
|
||||
-- "Edit your channel's broadcast configuration, including extension configuration. (This scope implies user:read:broadcast capability.)"
|
||||
has_user_edit_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit:follows"
|
||||
-- "Edit a user's follows."
|
||||
has_user_edit_follows BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:manage:blocked_users"
|
||||
-- "Manage the block list of a user."
|
||||
has_user_manage_blocked_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:blocked_users"
|
||||
-- "View the block list of a user."
|
||||
has_user_read_blocked_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:broadcast"
|
||||
-- "View a user's broadcasting configuration, including Extension configurations."
|
||||
has_user_read_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:email"
|
||||
-- "Read an authorized user's email address."
|
||||
has_user_read_email BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:follows"
|
||||
-- "View the list of channels a user follows."
|
||||
-- eg. We can use this to see if a Twitch user follows us.
|
||||
has_user_read_follows BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:subscriptions"
|
||||
-- "View if an authorized user is subscribed to specific channels."
|
||||
has_user_read_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "whispers:edit"
|
||||
-- "Send whisper messages."
|
||||
has_whispers_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "whispers:read"
|
||||
-- "View your whisper messages."
|
||||
has_whispers_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== SECURITY ==========
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- Incremented with every update.
|
||||
version INT UNSIGNED 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,
|
||||
|
||||
-- This is when the OAuth token will expire.
|
||||
-- While we need to refresh before this time, Twitch recommends against eager
|
||||
-- refreshes and instead wants the code to lazily refresh.
|
||||
-- This also has no bearing on the "refresh_token".
|
||||
-- We'll just use this for bookkeeping.
|
||||
expires_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- If the OAuth token is deleted, we set this.
|
||||
-- We'll need to set it for all of a user's OAuth tokens since this table stores many tokens.
|
||||
user_deleted_at TIMESTAMP NULL,
|
||||
mod_deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
KEY index_oauth_refresh_grouping_token (oauth_refresh_grouping_token),
|
||||
KEY fk_maybe_user_token (maybe_user_token),
|
||||
KEY index_twitch_user_id (twitch_user_id),
|
||||
-- KEY index_twitch_username (twitch_username),
|
||||
KEY index_twitch_username_lowercase (twitch_username_lowercase),
|
||||
KEY index_expires_at (expires_at),
|
||||
KEY index_user_deleted_at (user_deleted_at),
|
||||
KEY index_mod_deleted_at (mod_deleted_at)
|
||||
|
||||
-- KEY index_has_bits_read (has_bits_read),
|
||||
-- KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_bits_events;
|
||||
@@ -0,0 +1,44 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- This is primarily meant to be for analysis.
|
||||
-- NB: See [_docs/database_schema.md] for details on Twitch-specifics.
|
||||
|
||||
CREATE TABLE twitch_bits_events(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- ========== USER / CHANNEL ==========
|
||||
|
||||
-- The user sending the bits.
|
||||
-- We'll need to keep the name and lowercase for lookup.
|
||||
sender_twitch_user_id VARCHAR(64) NOT NULL,
|
||||
sender_twitch_username VARCHAR(32) NOT NULL,
|
||||
sender_twitch_username_lowercase VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The channel the bits were being sent to.
|
||||
-- We technically only need the ID since we can JOIN, but we'll keep
|
||||
-- the name for convenience.
|
||||
destination_channel_id VARCHAR(64) NOT NULL,
|
||||
destination_channel_name VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== BITS DETAILS ==========
|
||||
|
||||
is_anonymous BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- The number of bits just spent
|
||||
bits_used INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- The lifetime(?) number of bits spent by the user in this channel.
|
||||
total_bits_used INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
chat_message TEXT NOT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
KEY index_sender_twitch_user_id (sender_twitch_user_id),
|
||||
KEY index_sender_twitch_username_lowercase (sender_twitch_username_lowercase),
|
||||
KEY index_destination_channel_id (destination_channel_id)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_channel_point_events;
|
||||
@@ -0,0 +1,57 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- This is primarily meant to be for analysis.
|
||||
-- NB: See [_docs/database_schema.md] for details on Twitch-specifics.
|
||||
|
||||
CREATE TABLE twitch_channel_point_events (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- ========== USER / CHANNEL ==========
|
||||
|
||||
-- The user sending the bits.
|
||||
-- We'll need to keep the name and lowercase for lookup.
|
||||
sender_twitch_user_id VARCHAR(64) NOT NULL,
|
||||
sender_twitch_username VARCHAR(32) NOT NULL,
|
||||
sender_twitch_username_lowercase VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The channel the bits were being sent to.
|
||||
-- We technically only need the ID since we can JOIN, but we'll keep
|
||||
-- the name for convenience.
|
||||
destination_channel_id VARCHAR(64) NOT NULL,
|
||||
destination_channel_name VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== CHANNEL POINTS DETAILS ==========
|
||||
|
||||
-- This is the title used for the reward
|
||||
-- We'll match on this to do TTS
|
||||
title VARCHAR(256) NOT NULL,
|
||||
|
||||
-- This is the description used for the reward
|
||||
prompt VARCHAR(256) NOT NULL,
|
||||
|
||||
-- This is the text that the user sends
|
||||
-- This is optional, but we'll coerce null to empty
|
||||
user_text_input TEXT NOT NULL,
|
||||
|
||||
-- A UUID for this instance of reward redemption
|
||||
redemption_id VARCHAR(36) NOT NULL,
|
||||
|
||||
-- A UUID for the reward
|
||||
reward_id VARCHAR(36) NOT NULL,
|
||||
|
||||
reward_cost INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
is_sub_only BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
max_per_stream INT(10) UNSIGNED DEFAULT NULL,
|
||||
max_per_user_per_stream INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
KEY index_sender_twitch_user_id (sender_twitch_user_id),
|
||||
KEY index_sender_twitch_username_lowercase (sender_twitch_username_lowercase),
|
||||
KEY index_destination_channel_id (destination_channel_id)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,10 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_inference_jobs DROP COLUMN is_for_twitch;
|
||||
ALTER TABLE tts_inference_jobs DROP COLUMN is_from_api;
|
||||
ALTER TABLE tts_inference_jobs DROP COLUMN priority_level;
|
||||
|
||||
ALTER TABLE tts_results DROP COLUMN is_from_api;
|
||||
ALTER TABLE tts_results DROP COLUMN is_for_twitch;
|
||||
@@ -0,0 +1,23 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_inference_jobs
|
||||
ADD COLUMN is_from_api BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER creator_set_visibility,
|
||||
|
||||
ADD COLUMN is_for_twitch BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER is_from_api,
|
||||
|
||||
-- Priority *increases*, so a level of 2 will be higher than 1.
|
||||
-- By default, all jobs from FakeYou have level 0.
|
||||
-- Twitch TTS has level 1.
|
||||
-- Paid Twitch and Paid API have level 2.
|
||||
ADD COLUMN priority_level TINYINT UNSIGNED NOT NULL DEFAULT 0
|
||||
AFTER status;
|
||||
|
||||
ALTER TABLE tts_results
|
||||
ADD COLUMN is_from_api BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER duration_millis,
|
||||
ADD COLUMN is_for_twitch BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER is_from_api;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models DROP COLUMN is_front_page_featured;
|
||||
ALTER TABLE tts_models DROP COLUMN is_twitch_featured;
|
||||
@@ -0,0 +1,10 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN is_front_page_featured BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER version_string,
|
||||
|
||||
ADD COLUMN is_twitch_featured BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER is_front_page_featured;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_event_rules;
|
||||
@@ -0,0 +1,70 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- How to respond to different types of Twitch events.
|
||||
-- Multiple rows per user
|
||||
CREATE TABLE twitch_event_rules(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Foreign key to user
|
||||
-- This is a FakeYou/Storyteller account, *NOT* a twitch user id.
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== EVENT MATCHING AND BEHAVIOR ==========
|
||||
|
||||
-- What type of event we'll be responding to.
|
||||
event_category ENUM(
|
||||
'bits',
|
||||
'channel_points',
|
||||
'chat_command'
|
||||
) NOT NULL,
|
||||
|
||||
-- A JSON payload containing any predicates we wish to apply to the match.
|
||||
-- eg. bits_value > 100
|
||||
-- eg. channel_points_award_name == "Mario Voice"
|
||||
event_match_predicate MEDIUMTEXT NOT NULL,
|
||||
|
||||
-- A JSON payload containing how we wish to respond to the event.
|
||||
-- eg. tts M:model
|
||||
event_response MEDIUMTEXT NOT NULL,
|
||||
|
||||
-- ========== RULE ORGANIZATION AND MANAGEMENT ==========
|
||||
|
||||
-- The user can rearrange the rules in the UI.
|
||||
-- This will be the order they apply in if matched.
|
||||
-- NB: There is nothing in MySQL to guarantee unique ordering.
|
||||
user_specified_rule_order INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
-- Whether or not the rule is enabled.
|
||||
-- This is different than deleted. It still shows up in the UI.
|
||||
rule_is_disabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== ABUSE TRACKING, ETC. ==========
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_user_token (user_token),
|
||||
KEY index_event_category (event_category),
|
||||
KEY index_deleted_at (deleted_at)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_general_settings;
|
||||
@@ -0,0 +1,38 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- One row per user. Contains all of the general (non-repeated) configs.
|
||||
CREATE TABLE twitch_general_settings (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Foreign key to user
|
||||
-- This is a FakeYou/Storyteller account, *NOT* a twitch user id.
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Kill switch for the entire service.
|
||||
storyteller_is_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Kill switch for TTS.
|
||||
tts_is_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Kill switch for W2L.
|
||||
w2l_is_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Can set a fallback voice if a TTS voice goes missing.
|
||||
maybe_fallback_tts_model_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (user_token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE api_tokens;
|
||||
@@ -0,0 +1,47 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- We'll use application logic to kill any API keys beyond the most recent 5 "active" a user creates.
|
||||
CREATE TABLE api_tokens (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- This is a private internal reference to the API token.
|
||||
-- Not shared with consumers / users.
|
||||
-- This should be used as the foreign key for the token.
|
||||
internal_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- This is the secret API token value given to consumers
|
||||
api_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Foreign key to user that owns the API token.
|
||||
-- A user can have several.
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- A user-defined short description (optional)
|
||||
maybe_short_description VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
UNIQUE KEY (internal_token),
|
||||
UNIQUE KEY (api_token),
|
||||
KEY fk_user_token (user_token),
|
||||
KEY index_created_at (created_at),
|
||||
KEY index_deleted_at (deleted_at)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE voice_clone_requests;
|
||||
@@ -0,0 +1,77 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE voice_clone_requests(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== CONTACT ==========
|
||||
|
||||
-- Foreign key to user
|
||||
-- This is a FakeYou/Storyteller account, *NOT* a twitch user id.
|
||||
maybe_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
email_address VARCHAR(255) NOT NULL,
|
||||
|
||||
discord_username VARCHAR(255) NOT NULL,
|
||||
|
||||
-- ========== REASON ==========
|
||||
|
||||
-- Visibility
|
||||
is_for_private_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_public_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- How they'll use
|
||||
is_for_studio BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_twitch_tts BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_api_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_music BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_games BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_other BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
optional_notes_on_use MEDIUMTEXT DEFAULT NULL,
|
||||
|
||||
-- Subject/Ownership
|
||||
is_own_voice BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_third_party_voice BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
optional_notes_on_subject VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== RECORDING QUALITY / EQUIPMENT ==========
|
||||
|
||||
has_clean_audio_recordings BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
has_good_microphone BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== COMMENTS ==========
|
||||
|
||||
optional_questions MEDIUMTEXT DEFAULT NULL,
|
||||
optional_extra_comments MEDIUMTEXT DEFAULT NULL,
|
||||
|
||||
-- ========== BUSINESS END / INTERNAL USE ==========
|
||||
|
||||
internal_has_been_handled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
internal_notes MEDIUMTEXT DEFAULT NULL,
|
||||
|
||||
-- ========== ABUSE TRACKING, ETC. ==========
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
ip_address_creation VARCHAR(40) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_maybe_user_token (maybe_user_token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,9 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN ietf_language_tag;
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN ietf_primary_language_subtag;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en'
|
||||
AFTER maybe_default_pretrained_vocoder;
|
||||
|
||||
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es")
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en'
|
||||
AFTER ietf_language_tag;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE tts_models
|
||||
DROP COLUMN maybe_suggested_unique_bot_command;
|
||||
@@ -0,0 +1,14 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- A bot command prefix, eg. 'sonic' that could be interpreted as '/sonic' by a TTS system.
|
||||
-- These are unique strings and can only be applied to one model at a time.
|
||||
-- Only moderators can set this, and it's only for the best voices.
|
||||
ALTER TABLE tts_models
|
||||
ADD COLUMN maybe_suggested_unique_bot_command VARCHAR(255) DEFAULT NULL
|
||||
AFTER is_twitch_featured;
|
||||
|
||||
-- And the unique index.
|
||||
ALTER TABLE tts_models
|
||||
ADD UNIQUE INDEX unique_index_maybe_suggested_unique_bot_command (maybe_suggested_unique_bot_command);
|
||||
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE twitch_oauth_tokens
|
||||
DROP COLUMN internal_token;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- In case we ever want to query these via an admin interface, it'd be nice to not use IDs
|
||||
ALTER TABLE twitch_oauth_tokens
|
||||
ADD COLUMN internal_token VARCHAR(32) NOT NULL
|
||||
AFTER id;
|
||||
|
||||
-- And the unique index.
|
||||
ALTER TABLE twitch_oauth_tokens
|
||||
ADD UNIQUE INDEX unique_index_internal_token (internal_token);
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE twitch_event_match_logs;
|
||||
@@ -0,0 +1,23 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Log any event matching (bits, channel points, etc.)
|
||||
CREATE TABLE twitch_event_match_logs(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Type of event, eg.
|
||||
event_type VARCHAR(32) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,120 @@
|
||||
-- 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
|
||||
|
||||
CREATE TABLE tts_inference_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token from client
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS ==========
|
||||
|
||||
-- The model to use.
|
||||
-- This also determines which architecture we're using.
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- If set, use a different pretrained vocoder.
|
||||
maybe_override_pretrained_vocoder VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- The raw, unprocessed user input.
|
||||
raw_inference_text TEXT NOT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- Foreign key to user
|
||||
-- If no user is logged in, this is null.
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== SOURCE METADATA ==========
|
||||
|
||||
is_from_api BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_twitch BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- Priority *increases*, so a level of 2 will be higher than 1.
|
||||
-- These are the level semantics currently:
|
||||
-- - All jobs from anonymous FakeYou users have level 0.
|
||||
-- - All jobs from logged in FakeYou users have level 1.
|
||||
-- - All jobs from Twitch TTS (unpaid) have level 10 (ten).
|
||||
-- - (There will be future levels for paid Twitch and social FakeYou rewards.)
|
||||
priority_level TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,120 @@
|
||||
-- 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
|
||||
|
||||
-- TTS MODELS
|
||||
CREATE TABLE tts_model_upload_jobs (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
-- This is so the in-progress results can be looked up by the UI.
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- Idempotency token
|
||||
-- This is so the frontend client doesn't submit duplicate jobs.
|
||||
uuid_idempotency_token VARCHAR(36) NOT NULL,
|
||||
|
||||
-- ========== SUCCESS CASE ==========
|
||||
|
||||
-- If the job completes successfully, this is the result token.
|
||||
-- This is only populated on a successful result.
|
||||
on_success_result_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UPLOAD DETAILS ==========
|
||||
|
||||
-- The name of the voice
|
||||
-- The "name" of the voice model, which might be complicated.
|
||||
-- If maybe_subject_token (etc.) is set, then it's authoritative instead.
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes',
|
||||
'talknet'
|
||||
) NOT NULL DEFAULT 'not-set',
|
||||
|
||||
-- Can be linked to a well-known voice
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we need to download the file from Google Drive.
|
||||
download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- NB: DO NOT SORT!
|
||||
-- download_url_type ENUM(
|
||||
-- 'google-drive',
|
||||
-- 'web'
|
||||
-- ) NOT NULL DEFAULT 'web',
|
||||
|
||||
-- ========== CREATOR DETAILS AND PREFERENCES ==========
|
||||
|
||||
-- Foreign key to user
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== JOB SYSTEM DETAILS ==========
|
||||
|
||||
-- Jobs begin as "pending", then transition to other states.
|
||||
--
|
||||
-- * Pending = job is ready to go
|
||||
-- * Started = job is running
|
||||
-- * Complete_Success = job is done (success)
|
||||
-- * Complete_Failure = job is done (failure)
|
||||
-- * Attempt_Failed = job failed but may retry.
|
||||
-- * Dead = job failed permanently.
|
||||
--
|
||||
-- Pending -> Started -> Complete_Success
|
||||
-- |-> Complete_Failure
|
||||
-- \-> Attempt_Failed -> Started -> { Complete, Failed, Dead }
|
||||
status ENUM(
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success',
|
||||
'complete_failure',
|
||||
'attempt_failed',
|
||||
'dead') NOT NULL DEFAULT 'pending',
|
||||
|
||||
-- We can track this against a "max_attempt_count"
|
||||
attempt_count INT(3) NOT NULL DEFAULT 0,
|
||||
|
||||
-- If there is a failure, tell the user why.
|
||||
failure_reason VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Failed jobs will set a next attempt time.
|
||||
-- Subsequent tries can increase the timeout.
|
||||
-- Failures because of permissions require human intervention => [retry_at=null].
|
||||
-- Failures because of invalid files are dead => [status=dead].
|
||||
retry_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (uuid_idempotency_token),
|
||||
KEY fk_on_success_result_token (on_success_result_token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY index_status (status),
|
||||
KEY index_creator_ip_address (creator_ip_address)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,204 @@
|
||||
-- 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
|
||||
|
||||
CREATE TABLE tts_models (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
tts_model_type ENUM(
|
||||
'not-set',
|
||||
'tacotron2',
|
||||
'glowtts',
|
||||
'glowtts-vocodes',
|
||||
'talknet'
|
||||
) NOT NULL DEFAULT 'not-set',
|
||||
|
||||
-- For models distributed as archives/bundles (eg. TalkNet), we can pack
|
||||
-- in a vocoder. Note that this vocoder does not have to be used.
|
||||
has_self_contained_vocoder BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- For models distributed as archives/bundles (eg. TalkNet), we can pack
|
||||
-- in a duration model.
|
||||
has_self_contained_duration_model BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- For models distributed as archives/bundles (eg. TalkNet), we can pack
|
||||
-- in a pitch model.
|
||||
has_self_contained_pitch_model BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- NB: DO NOT CHANGE ORDER; APPEND ONLY!
|
||||
-- How text should be handled.
|
||||
text_preprocessing_algorithm ENUM(
|
||||
'basic',
|
||||
'arpabet'
|
||||
) NOT NULL DEFAULT 'basic',
|
||||
|
||||
-- If set, use a different pretrained vocoder.
|
||||
-- If not set, use the website default. (Currently HifiGan-SS)
|
||||
maybe_default_pretrained_vocoder VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- Optional Pointer to a newer version of the voice
|
||||
-- If there's a newer version, we can disable this one.
|
||||
-- maybe_updated_model_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- We can set as a combination of ['username' + 'voice-name']
|
||||
-- There can be public aliases for voices, eg. a voice's default model.
|
||||
-- A user can change this.
|
||||
-- As such, these should not be foreign keys.
|
||||
-- updatable_slug VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Can be linked to a well-known voice
|
||||
-- maybe_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
-- maybe_actor_subject_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== UNSTRUCTURED METADATA ==========
|
||||
|
||||
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
|
||||
ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en',
|
||||
|
||||
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es")
|
||||
ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en',
|
||||
|
||||
-- The "name" of the voice model, which might be complicated.
|
||||
-- If maybe_subject_token (etc.) is set, then it's authoritative instead.
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
||||
-- The description of the model in markdown.
|
||||
description_markdown TEXT NOT NULL,
|
||||
|
||||
-- Generated HTML (not user-editable).
|
||||
description_rendered_html TEXT NOT NULL,
|
||||
|
||||
-- eg. Bill Clinton, Batman, or Goku.
|
||||
voice_name VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. Sean Schemmel
|
||||
actor_name VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. if the voice is "happy" or a singer "a-capella", etc.
|
||||
characteristic VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Optional; eg. if you train the model more than once.
|
||||
version_string VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- Whether the voice features on the front of FakeYou or Storyteller Twitch TTS
|
||||
is_front_page_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_twitch_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- A suggested bot command prefix, eg. 'sonic' that could be interpreted as '/sonic'
|
||||
-- by a TTS system. These are unique strings that can only be applied to one model at
|
||||
-- a time at most. Only moderators can set this, and it's only for the best voices.
|
||||
maybe_suggested_unique_bot_command VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- ========== IMMUTABLE PROVENANCE AND METADATA ==========
|
||||
|
||||
-- Where the file was originally downloaded (if it was downloaded)
|
||||
original_download_url VARCHAR(512) DEFAULT NULL,
|
||||
|
||||
-- The filename that was used at upload time (if available)
|
||||
original_filename VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- File characteristics
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
creator_user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- For abuse tracking.
|
||||
-- Wide enough for IPv4/6
|
||||
creator_ip_address_creation VARCHAR(40) NOT NULL,
|
||||
creator_ip_address_last_update VARCHAR(40) NOT NULL,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
creator_set_visibility ENUM(
|
||||
'public',
|
||||
'hidden',
|
||||
'private'
|
||||
) NOT NULL DEFAULT 'public',
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- The pytorch model
|
||||
-- For now, this will be a hash of the file contents.
|
||||
-- NB: NOT UNIQUE! We can allow duplicate uploads.
|
||||
private_bucket_hash CHAR(64) NOT NULL,
|
||||
-- The "full url" version of the path
|
||||
private_bucket_object_name VARCHAR(255) NOT NULL,
|
||||
|
||||
-- Whether the file is a zip archive (rather than a model file).
|
||||
private_bucket_object_is_archive BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== RATING AND RANKING ==========
|
||||
|
||||
-- Calculated average, on a scale of 0-100
|
||||
-- Null with zero ratings.
|
||||
-- calculated_average_score INT(3) DEFAULT NULL,
|
||||
|
||||
-- Other metrics
|
||||
-- calculated_total_ratings_submitted_count INT(10) NOT NULL DEFAULT 0,
|
||||
-- calculated_total_uses_count BIGINT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- Mods have to approve of tts models for them to show up in a public index.
|
||||
-- Models can be used by the author (or other parties that know the URL) before
|
||||
-- they're approved, but unapproved models won't show up in public indices.
|
||||
-- This is independent of other visibility controls (is_mod_disabled, deleted_at,
|
||||
-- and creator_set_visibility)
|
||||
is_public_listing_approved BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- Extremely popular models may be locked from deletion or modification by users.
|
||||
is_locked_from_user_modification BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- In this case, a moderator disables it from being used for inference.
|
||||
-- This also disables it for the creator.
|
||||
-- Unlike deletion, it remains "visible" to those that have access.
|
||||
is_locked_from_use BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- If a moderator has comments.
|
||||
maybe_mod_comments VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- The last moderator that made changes.
|
||||
maybe_mod_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- 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,
|
||||
|
||||
-- If this is removed by a mod.
|
||||
-- It completely disappears from the system.
|
||||
user_deleted_at TIMESTAMP NULL,
|
||||
mod_deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_creator_user_token (creator_user_token),
|
||||
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
|
||||
KEY index_creator_ip_address_creation (creator_ip_address_creation),
|
||||
KEY index_creator_ip_address_last_update (creator_ip_address_last_update),
|
||||
KEY index_creator_set_visibility (creator_set_visibility),
|
||||
KEY index_private_bucket_hash (private_bucket_hash),
|
||||
KEY index_is_public_listing_approved (is_public_listing_approved),
|
||||
KEY index_is_locked_from_user_modification (is_locked_from_user_modification),
|
||||
KEY index_is_locked_from_use (is_locked_from_use)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -0,0 +1,105 @@
|
||||
-- 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
|
||||
|
||||
CREATE TABLE tts_results (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== INFERENCE DETAILS ==========
|
||||
|
||||
-- The TTS model that was used
|
||||
model_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- If set, specifies which pretrained vocoder was used.
|
||||
maybe_pretrained_vocoder_used VARCHAR(64) DEFAULT NULL,
|
||||
|
||||
-- The original raw, unprocessed user input.
|
||||
raw_inference_text TEXT NOT NULL,
|
||||
|
||||
-- SHA2 hash of the text [SHA2 = CHAR(64), SHA1 = CHAR(40), MD5 = CHAR(32)]
|
||||
raw_inference_text_hash_sha2 CHAR(64) NOT NULL,
|
||||
|
||||
-- First pass at text normalization.
|
||||
-- eg. 14th -> fourteenth, etc.
|
||||
normalized_inference_text TEXT NOT NULL,
|
||||
|
||||
-- If the model uses arpabet, we'll save the arpabet we used.
|
||||
maybe_arpabet_text TEXT DEFAULT NULL,
|
||||
|
||||
-- ========== CREATOR DETAILS ==========
|
||||
|
||||
-- The person that created the template.
|
||||
-- If the user wasn't logged in, this is null
|
||||
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,
|
||||
|
||||
-- (THIS MIGHT NOT BE USED)
|
||||
-- NB: DO NOT SORT!
|
||||
-- THIS MUST MATCH THE RESPECTIVE JOBS TABLE.
|
||||
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,
|
||||
|
||||
-- ========== BUCKET STORAGE ==========
|
||||
|
||||
-- Where the wav, spectrogram, and etc. are located.
|
||||
public_bucket_wav_audio_path VARCHAR(255) NOT NULL,
|
||||
public_bucket_spectrogram_path VARCHAR(255) NOT NULL,
|
||||
|
||||
-- ========== METADATA ==========
|
||||
|
||||
file_size_bytes INT(10) NOT NULL DEFAULT 0,
|
||||
duration_millis INT(10) NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== SOURCE METADATA ==========
|
||||
|
||||
is_from_api BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_for_twitch BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== MODERATION DETAILS ==========
|
||||
|
||||
-- The last moderator that made changes.
|
||||
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,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY fk_model_token (model_token),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY fk_maybe_creator_anonymous_visitor_token (maybe_creator_anonymous_visitor_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,75 @@
|
||||
|
||||
-- All logged in users with results in the last X days
|
||||
select u.created_at from users as u
|
||||
where u.token IN
|
||||
(select distinct u.token from tts_inference_jobs as j join users u on u.token = j.maybe_creator_user_token where j.created_at > now() - interval 7 day)
|
||||
order by u.created_at ASC;
|
||||
|
||||
|
||||
-- All logged in users with results in the last X days that are older than Y
|
||||
select u.created_at from users as u
|
||||
where u.token IN
|
||||
(select distinct u.token from tts_inference_jobs as j join users u on u.token = j.maybe_creator_user_token where j.created_at > now() - interval 30 day)
|
||||
AND u.created_at < now() - interval 30 day
|
||||
order by u.created_at ASC;
|
||||
|
||||
-- ====================== FEBRUARY COHORT ===================================
|
||||
|
||||
-- [1] All users created between X and Y
|
||||
select count(*) from users
|
||||
where created_at > now() - interval 60 day
|
||||
and created_at < now() - interval 30 day;
|
||||
|
||||
-- [2] Active users from that cohort ^
|
||||
select count(*) from users as u
|
||||
where u.token IN
|
||||
(select distinct u.token from tts_inference_jobs as j join users u on u.token = j.maybe_creator_user_token where j.created_at > now() - interval 30 day)
|
||||
AND created_at > now() - interval 60 day
|
||||
AND created_at < now() - interval 30 day;
|
||||
|
||||
|
||||
|
||||
-- ====================== JANUARY COHORT ===================================
|
||||
|
||||
-- [1] All users created between X and Y
|
||||
select count(*) from users
|
||||
where created_at > now() - interval 90 day
|
||||
and created_at < now() - interval 60 day;
|
||||
|
||||
-- [2] Active users from that cohort ^
|
||||
select count(*) from users as u
|
||||
where u.token IN
|
||||
(select distinct u.token from tts_inference_jobs as j join users u on u.token = j.maybe_creator_user_token where j.created_at > now() - interval 30 day)
|
||||
AND created_at > now() - interval 90 day
|
||||
AND created_at < now() - interval 60 day;
|
||||
|
||||
|
||||
|
||||
(select distinct u.token from tts_inference_jobs as j join users u on u.token = j.maybe_creator_user_token where j.created_at > now() - interval 30 day)
|
||||
|
||||
|
||||
select j.creator_ip_address, count(*) as number
|
||||
from tts_inference_jobs as j
|
||||
where j.created_at > now() - interval 1 day
|
||||
group by j.creator_ip_address
|
||||
order by number desc
|
||||
limit 100;
|
||||
|
||||
|
||||
select count(*) from tts_inference_jobs
|
||||
where created_at > now() - interval 1 day ;
|
||||
|
||||
select count(distinct creator_ip_address) from tts_inference_jobs
|
||||
where created_at > now() - interval 1 day ;
|
||||
|
||||
|
||||
|
||||
select j.creator_ip_address, count(*) as number
|
||||
from tts_inference_jobs as j
|
||||
where j.created_at > now() - interval 1 day
|
||||
group by j.creator_ip_address
|
||||
order by number desc
|
||||
limit 100;
|
||||
|
||||
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This is complicated since we're now in a more complex Rust workspace with
|
||||
# multiple projects and targets.
|
||||
|
||||
# NB(2022-01-31): For some reason, 'storyteller-web', despite importing the obs queries
|
||||
# via the `database_queries` shared library, started to exclude these queries. It was
|
||||
# working, but mysteriously stopped. I'm using this more complicated setup with jq-based
|
||||
# json merge as a stop gap.
|
||||
|
||||
# NB: This format can be used without changing directory:
|
||||
# SQLX_OFFLINE=true cargo sqlx prepare -- --bin storyteller-web --manifest-path crates/service/storyteller_web/Cargo.toml
|
||||
|
||||
build_shared_database_library() {
|
||||
pushd crates/lib/database_queries
|
||||
SQLX_OFFLINE=true cargo sqlx prepare
|
||||
popd
|
||||
}
|
||||
|
||||
build_storyteller_web_app() {
|
||||
# NB: This imports the inference/upload job queries
|
||||
# It should also import the shared database lib queries, but something(???) broke.
|
||||
pushd crates/service/storyteller_web
|
||||
SQLX_OFFLINE=true cargo sqlx prepare -- --bin storyteller-web # NB: Because multiple binary targets
|
||||
popd
|
||||
}
|
||||
|
||||
combine_sqlx_queries() {
|
||||
# Merge multiple JSON files into a single dictionary.
|
||||
# https://stackoverflow.com/a/24904276
|
||||
jq -s '.[0] * .[1]' \
|
||||
crates/lib/database_queries/sqlx-data.json \
|
||||
crates/service/storyteller_web/sqlx-data.json \
|
||||
> sqlx-data.json
|
||||
}
|
||||
|
||||
cleanup_temp_files() {
|
||||
rm crates/lib/database_queries/sqlx-data.json \
|
||||
crates/service/storyteller_web/sqlx-data.json
|
||||
}
|
||||
|
||||
build_shared_database_library
|
||||
build_storyteller_web_app
|
||||
combine_sqlx_queries
|
||||
cleanup_temp_files
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "config"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "config"
|
||||
path = "src/lib.rs"
|
||||
@@ -0,0 +1 @@
|
||||
pub mod shared_constants;
|
||||
@@ -0,0 +1,20 @@
|
||||
//! Shared constants that all binaries use.
|
||||
//! Or at least that deserve extremely high visibility.
|
||||
|
||||
/// NB: `sqlx::query` is spammy and dumps all queries as "info"-level log lines.
|
||||
/// NB: `hyper::proto::h1::io` is incredibly spammy and logs every chunk of bytes in very large files being downloaded.
|
||||
pub const DEFAULT_RUST_LOG: &'static str = "debug,actix_web=info,sqlx::query=warn,hyper::proto::h1::io=warn,storyteller_web::threads::db_health_checker_thread::db_health_checker_thread=warn";
|
||||
//const DEFAULT_RUST_LOG: &'static str = "debug,actix_web=info"; // but sometimes we want to debug
|
||||
|
||||
/// The default Redis connection string for use in development
|
||||
pub const DEFAULT_REDIS_DATABASE_0_CONNECTION_STRING: &'static str = "redis://localhost/0";
|
||||
|
||||
/// The default Redis connection string for use in development
|
||||
/// Database 1
|
||||
pub const DEFAULT_REDIS_DATABASE_1_CONNECTION_STRING: &'static str = "redis://localhost/1";
|
||||
|
||||
/// The default MySql connection string for use in development
|
||||
pub const DEFAULT_MYSQL_CONNECTION_STRING: &'static str = "mysql://storyteller:password@localhost/storyteller";
|
||||
|
||||
/// The number of results we return by default for paginated queries.
|
||||
pub const DEFAULT_MYSQL_QUERY_RESULT_PAGE_SIZE: u16 = 25;
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "container_common"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "container_common"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
|
||||
# External
|
||||
anyhow = "1.0.40"
|
||||
once_cell = "1.9.0"
|
||||
rand = "0.8.3"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
@@ -0,0 +1,2 @@
|
||||
/// Easier to import than anyhow::Result.
|
||||
pub type AnyhowResult<T> = anyhow::Result<T>;
|
||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
||||
pub mod random_from_vec;
|
||||
@@ -0,0 +1,31 @@
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
/// Return a random item from a vec.
|
||||
pub fn random_from_vec<T>(vec: &Vec<T>) -> Option<&T> {
|
||||
vec.choose(&mut rand::thread_rng())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::collections::random_from_vec::random_from_vec;
|
||||
|
||||
#[test]
|
||||
fn pulls_item_from_vec() {
|
||||
let items = vec!["one", "two", "three"];
|
||||
let selected = random_from_vec(&items).unwrap();
|
||||
assert!(items.contains(selected));
|
||||
|
||||
let items = vec!["one", "two", "three"].into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let selected = random_from_vec(&items).unwrap();
|
||||
assert!(items.contains(selected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn behavior_on_empty() {
|
||||
let items : Vec<String> = vec![];
|
||||
let selected = random_from_vec(&items);
|
||||
assert!(selected.is_none());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod supported_languages_for_models;
|
||||
@@ -0,0 +1,112 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
|
||||
/// These are language tags we try to support.
|
||||
static SUPPORTED_LANGUAGES_FOR_MODELS : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
let language_tags = [
|
||||
|
||||
// ========== Technically, we only support these so far ==========
|
||||
|
||||
// English
|
||||
"en",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-GB",
|
||||
"en-US",
|
||||
// Spanish
|
||||
"es",
|
||||
"es-419",
|
||||
"es-AR",
|
||||
"es-CL",
|
||||
"es-CO",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"es-PE",
|
||||
"es-US",
|
||||
// Portuguese
|
||||
"pt",
|
||||
"pt-BR",
|
||||
|
||||
// ========== But these are on the horizon ==========
|
||||
|
||||
// French
|
||||
"fr",
|
||||
"fr-FR",
|
||||
// German
|
||||
"de",
|
||||
"de-DE",
|
||||
// Japanese
|
||||
"ja",
|
||||
"ja-JP",
|
||||
// Misc
|
||||
"id",
|
||||
"id-ID",
|
||||
"it",
|
||||
"it-IT",
|
||||
"ru",
|
||||
"ru-RU",
|
||||
"th-TH",
|
||||
"tr",
|
||||
"tr-TR",
|
||||
"zh-CN",
|
||||
"zh-HK",
|
||||
];
|
||||
language_tags.iter()
|
||||
.map(|tag| tag.to_string())
|
||||
.collect::<HashSet<String>>()
|
||||
});
|
||||
|
||||
/// Convert lower case tags to canonical form
|
||||
static SUPPORTED_LANGUAGES_FOR_MODELS_CANONICAL_MAP : Lazy<HashMap<String, String>> = Lazy::new(|| {
|
||||
SUPPORTED_LANGUAGES_FOR_MODELS.iter()
|
||||
.map(|tag| (tag.to_lowercase(), tag.clone()))
|
||||
.collect::<HashMap<_,_>>()
|
||||
});
|
||||
|
||||
/// Take a full IETF BCP 47 language tag and return the canonicalized form *IF* we support it
|
||||
pub fn get_canonicalized_language_tag_for_model(language_tag: &str) -> Option<&'static str> {
|
||||
let lowercase = language_tag.to_lowercase();
|
||||
SUPPORTED_LANGUAGES_FOR_MODELS_CANONICAL_MAP.get(&lowercase).map(|v| v.as_str())
|
||||
}
|
||||
|
||||
/// Take a full IETF BCP 47 language tag and return true *IF* we support it
|
||||
/// It must be the correct case.
|
||||
pub fn is_valid_language_for_models(language_tag: &str) -> bool {
|
||||
SUPPORTED_LANGUAGES_FOR_MODELS.contains(language_tag)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::i18n::supported_languages_for_models::{get_canonicalized_language_tag_for_model, is_valid_language_for_models};
|
||||
|
||||
#[test]
|
||||
fn get_canonical_language_for_model_success() {
|
||||
assert_eq!("en", get_canonicalized_language_tag_for_model("EN").unwrap());
|
||||
assert_eq!("es-419", get_canonicalized_language_tag_for_model("ES-419").unwrap());
|
||||
assert_eq!("en-US", get_canonicalized_language_tag_for_model("En-Us").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_canonical_language_for_model_failure() {
|
||||
assert!(get_canonicalized_language_tag_for_model("").is_none());
|
||||
assert!(get_canonicalized_language_tag_for_model("en-JP").is_none());
|
||||
assert!(get_canonicalized_language_tag_for_model("es-Lots-Of-Tags").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_language_for_model() {
|
||||
// Valid
|
||||
assert!(is_valid_language_for_models("en"));
|
||||
assert!(is_valid_language_for_models("es-419"));
|
||||
assert!(is_valid_language_for_models("ja-JP"));
|
||||
// Invalid due to case
|
||||
assert!(!is_valid_language_for_models("EN"));
|
||||
assert!(!is_valid_language_for_models("ES-419"));
|
||||
assert!(!is_valid_language_for_models("JA-jp"));
|
||||
// Invalid misc
|
||||
assert!(!is_valid_language_for_models(""));
|
||||
assert!(!is_valid_language_for_models("foo"));
|
||||
assert!(!is_valid_language_for_models("en-FOO"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod anyhow_result;
|
||||
pub mod collections;
|
||||
pub mod i18n;
|
||||
pub mod numerics;
|
||||
pub mod thread;
|
||||
pub mod token;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod signed_to_unsigned;
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
// TODO: Use macros to define these (or use a better numeric crate)
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn i8_to_unsigned_zeroing_negatives(num: i8) -> u8 {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn i16_to_unsigned_zeroing_negatives(num: i16) -> u16 {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn i32_to_unsigned_zeroing_negatives(num: i32) -> u32 {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn i64_to_unsigned_zeroing_negatives(num: i64) -> u64 {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn i128_to_unsigned_zeroing_negatives(num: i128) -> u128 {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative numbers coalesce to 0
|
||||
pub fn isize_to_unsigned_zeroing_negatives(num: isize) -> usize {
|
||||
if num.is_negative() {
|
||||
0
|
||||
} else {
|
||||
num.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::numerics::signed_to_unsigned::i8_to_unsigned_zeroing_negatives;
|
||||
use crate::numerics::signed_to_unsigned::i16_to_unsigned_zeroing_negatives;
|
||||
use crate::numerics::signed_to_unsigned::i32_to_unsigned_zeroing_negatives;
|
||||
use crate::numerics::signed_to_unsigned::i64_to_unsigned_zeroing_negatives;
|
||||
use crate::numerics::signed_to_unsigned::i128_to_unsigned_zeroing_negatives;
|
||||
use crate::numerics::signed_to_unsigned::isize_to_unsigned_zeroing_negatives;
|
||||
|
||||
#[test]
|
||||
fn i8_to_unsigned() {
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(i8_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i16_to_unsigned() {
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(i16_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i32_to_unsigned() {
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(i32_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn i64_to_unsigned() {
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(i64_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn i128_to_unsigned() {
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(i128_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn isize_to_unsigned() {
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(-127), 0);
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(-1), 0);
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(0), 0);
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(1), 1);
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(100), 100);
|
||||
assert_eq!(isize_to_unsigned_zeroing_negatives(127), 127);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod thread_id;
|
||||
@@ -0,0 +1,59 @@
|
||||
use crate::token::random_crockford_token::random_crockford_token;
|
||||
|
||||
/// Thread string identifiers
|
||||
/// Used for leases, logging, etc.
|
||||
/// This has nothing to do with actual OS thread names or IDs.
|
||||
/// The `std::thread::ThreadId` type might be better for some cases.
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct ThreadId {
|
||||
id: String,
|
||||
}
|
||||
|
||||
impl ThreadId {
|
||||
pub fn random_id() -> Self {
|
||||
Self {
|
||||
id: random_crockford_token(10),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_id(id: &str) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> &str {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::thread::thread_id::ThreadId;
|
||||
|
||||
#[test]
|
||||
fn equals() {
|
||||
let a = ThreadId::with_id("foo");
|
||||
let b = ThreadId::with_id("foo");
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_equals() {
|
||||
let a = ThreadId::with_id("foo");
|
||||
let b = ThreadId::with_id("bar");
|
||||
assert_ne!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manual_id() {
|
||||
let t = ThreadId::with_id("foo");
|
||||
assert_eq!("foo", t.get_id());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_id() {
|
||||
let t = ThreadId::random_id();
|
||||
assert_eq!(t.get_id().len(), 10);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod random_crockford_token;
|
||||
pub mod random_prefix_crockford_token;
|
||||
pub mod random_uuid;
|
||||
@@ -0,0 +1,30 @@
|
||||
use rand::Rng;
|
||||
|
||||
// Crockford characters
|
||||
const CROCKFORD_CHARSET: &[u8] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||||
|
||||
pub fn random_crockford_token(length: usize) -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let token: String = (0..length)
|
||||
.map(|_| {
|
||||
let idx = rng.gen_range(0..CROCKFORD_CHARSET.len());
|
||||
CROCKFORD_CHARSET[idx] as char
|
||||
})
|
||||
.collect();
|
||||
|
||||
token
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::token::random_crockford_token::random_crockford_token;
|
||||
|
||||
#[test]
|
||||
fn random_token_length() {
|
||||
assert_eq!(random_crockford_token(0), "".to_string());
|
||||
assert_eq!(random_crockford_token(1).len(), 1);
|
||||
assert_eq!(random_crockford_token(10).len(), 10);
|
||||
assert_eq!(random_crockford_token(32).len(), 32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use anyhow::anyhow;
|
||||
use crate::anyhow_result::AnyhowResult;
|
||||
use rand::Rng;
|
||||
|
||||
// Crockford characters
|
||||
const CROCKFORD_UPPERCASE_CHARSET: &[u8] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||||
|
||||
const CROCKFORD_LOWERCASE_CHARSET: &[u8] = b"0123456789abcdefghjkmnpqrstvwxyz";
|
||||
|
||||
// Random part can't be any less than this.
|
||||
const MIN_ENTROPY_LENGTH : usize = 8;
|
||||
|
||||
pub fn random_prefix_crockford_token(prefix: &str, length: usize, uppercase: bool) -> AnyhowResult<String> {
|
||||
let mut prefix = prefix.trim().to_string();
|
||||
|
||||
if prefix.is_empty() {
|
||||
return Err(anyhow!("prefix not set; use other crockford functions"));
|
||||
}
|
||||
|
||||
if !prefix.ends_with(":") {
|
||||
prefix = format!("{}:", prefix);
|
||||
}
|
||||
|
||||
let entropy_length : usize = length.saturating_sub(prefix.len());
|
||||
|
||||
if entropy_length < MIN_ENTROPY_LENGTH {
|
||||
return Err(anyhow!("not enough entropy in token"));
|
||||
}
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let charset = if uppercase { CROCKFORD_UPPERCASE_CHARSET } else { CROCKFORD_LOWERCASE_CHARSET };
|
||||
|
||||
let entropy_part: String = (0..entropy_length)
|
||||
.map(|_| {
|
||||
let idx = rng.gen_range(0..charset.len());
|
||||
charset[idx] as char
|
||||
})
|
||||
.collect();
|
||||
|
||||
let token = format!("{}{}", prefix, entropy_part);
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::token::random_prefix_crockford_token::random_prefix_crockford_token;
|
||||
|
||||
#[test]
|
||||
fn no_prefix_error() {
|
||||
assert!(random_prefix_crockford_token("", 0, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 10, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 32, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 0, true).is_err());
|
||||
assert!(random_prefix_crockford_token("", 10, true).is_err());
|
||||
assert!(random_prefix_crockford_token("", 32, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_enough_entropy_error() {
|
||||
assert!(random_prefix_crockford_token("foo", 0, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 5, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 11, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo:", 11, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 0, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 5, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 11, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo:", 11, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn starts_with() {
|
||||
assert!(random_prefix_crockford_token("w", 10, false).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, false).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("prefix", 16, false).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("prefix:", 16, false).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, true).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, true).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("prefix", 16, true).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("prefix:", 16, true).unwrap().starts_with("prefix:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length() {
|
||||
assert_eq!(random_prefix_crockford_token("w", 10, false).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("w:", 10, false).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("prefix", 16, false).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("prefix:", 16, false).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("asdf:", 32, false).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("asdf", 32, false).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("w", 10, true).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("w:", 10, true).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("prefix", 16, true).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("prefix:", 16, true).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("asdf:", 32, true).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("asdf", 32, true).unwrap().len(), 32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn generate_random_uuid() -> String {
|
||||
let uuid = Uuid::new_v4();
|
||||
let mut buffer = Uuid::encode_buffer();
|
||||
let hyphenated_uuid = uuid.to_hyphenated()
|
||||
.encode_lower(&mut buffer);
|
||||
hyphenated_uuid.to_string()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
[package]
|
||||
name = "database_queries"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "database_queries"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Internal
|
||||
config = { path = "../config" }
|
||||
container_common = { path = "../container_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.40"
|
||||
base64 = "0.13.0"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.14"
|
||||
|
||||
# Needed to safety check some queries we can't use escaping for
|
||||
once_cell = "1.9.0"
|
||||
regex = "1.5.4"
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.64"
|
||||
toml = "0.5.8"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
#sqlx = { version = "0.4", features = [ "mysql", "runtime-tokio-native-tls", "offline", "chrono" ] }
|
||||
sqlx = { version = "0.5", features = [ "mysql", "runtime-actix-native-tls", "offline", "chrono" ] }
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
/// This is simply a semantic / literate way of saying
|
||||
/// an Optional should be required. There should be a
|
||||
/// better way to actually enforce this, though.
|
||||
pub (crate) type RequiredOption<T> = Option<T>;
|
||||
@@ -0,0 +1,44 @@
|
||||
//! These are columns where users can control the visibility of their data.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
/// To use this in a query, the query must have type annotations.
|
||||
/// See: https://www.gitmemory.com/issue/launchbadge/sqlx/1241/847154375
|
||||
/// eg. job_status as `job_status: crate::column_types::job_status::JobStatus`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, sqlx::Type)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[sqlx(rename_all = "snake_case")]
|
||||
pub enum JobStatus {
|
||||
Pending,
|
||||
Started,
|
||||
CompleteSuccess,
|
||||
CompleteFailure,
|
||||
AttemptFailed,
|
||||
Dead,
|
||||
}
|
||||
|
||||
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) -> AnyhowResult<Self> {
|
||||
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(anyhow!("invalid job_status: {:?}", job_status)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod job_status;
|
||||
pub mod record_visibility;
|
||||
pub mod tts_model_type;
|
||||
pub mod twitch_event_category;
|
||||
pub mod vocoder_type;
|
||||
@@ -0,0 +1,35 @@
|
||||
//! These are columns where users can control the visibility of their data.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
/// To use this in a query, the query must have type annotations.
|
||||
/// See: https://www.gitmemory.com/issue/launchbadge/sqlx/1241/847154375
|
||||
/// eg. preferred_tts_result_visibility as `preferred_tts_result_visibility: crate::column_types::record_visibility::RecordVisibility`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, sqlx::Type)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[sqlx(rename_all = "lowercase")]
|
||||
pub enum RecordVisibility {
|
||||
Public,
|
||||
Hidden,
|
||||
Private,
|
||||
}
|
||||
|
||||
impl RecordVisibility {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
RecordVisibility::Public => "public",
|
||||
RecordVisibility::Hidden => "hidden",
|
||||
RecordVisibility::Private => "private",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(record_visibility: &str) -> AnyhowResult<Self> {
|
||||
match record_visibility {
|
||||
"public" => Ok(RecordVisibility::Public),
|
||||
"hidden" => Ok(RecordVisibility::Hidden),
|
||||
"private" => Ok(RecordVisibility::Private),
|
||||
_ => Err(anyhow!("invalid value: {:?}", record_visibility)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//! These denote the TTS synthesizer model types
|
||||
|
||||
use anyhow::anyhow;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, sqlx::Type)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[sqlx(rename_all = "lowercase")]
|
||||
pub enum TtsModelType {
|
||||
#[serde(rename = "tacotron2")]
|
||||
Tacotron2,
|
||||
|
||||
#[serde(rename = "talknet")]
|
||||
Talknet,
|
||||
|
||||
// Currently unused enum values:
|
||||
//#[serde(rename = "not-set")]
|
||||
//NotSet,
|
||||
//#[serde(rename = "glowtts")]
|
||||
//GlowTts,
|
||||
//#[serde(rename = "glowtts-vocodes")]
|
||||
//GlowTtsVocodes,
|
||||
}
|
||||
|
||||
impl TtsModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
TtsModelType::Tacotron2 => "tacotron2",
|
||||
TtsModelType::Talknet => "talknet",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(vocoder_type: &str) -> AnyhowResult<Self> {
|
||||
match vocoder_type {
|
||||
"tacotron2" => Ok(TtsModelType::Tacotron2),
|
||||
"talknet" => Ok(TtsModelType::Talknet),
|
||||
_ => Err(anyhow!("invalid value: {:?}", vocoder_type)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//! These are columns where users can control the visibility of their data.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
/// To use this in a query, the query must have type annotations.
|
||||
/// See: https://www.gitmemory.com/issue/launchbadge/sqlx/1241/847154375
|
||||
/// eg. twitch_event_category as `twitch_event_category: crate::column_types::twitch_event_category::TwitchEventCategory`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, sqlx::Type)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[sqlx(rename_all = "snake_case")]
|
||||
pub enum TwitchEventCategory {
|
||||
Bits,
|
||||
ChannelPoints,
|
||||
ChatCommand,
|
||||
}
|
||||
|
||||
impl TwitchEventCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Bits => "bits",
|
||||
Self::ChannelPoints => "channel_points",
|
||||
Self::ChatCommand => "chat_command",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> AnyhowResult<Self> {
|
||||
match value {
|
||||
"bits" => Ok(Self::Bits),
|
||||
"channel_points" => Ok(Self::ChannelPoints),
|
||||
"chat_command" => Ok(Self::ChatCommand),
|
||||
_ => Err(anyhow!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1629 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user