Compare commits

..
1735 changed files with 60990 additions and 41624 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
hakari-package = "workspace-build-acceleration"
hakari-package = "my-workspace-hack"
resolver = "1"
@@ -11,4 +11,4 @@ platforms = [
"x86_64-pc-windows-msvc",
]
exact-versions = true
exact-versions = true
-63
View File
@@ -1,63 +0,0 @@
name: 'publish'
on:
push:
branches:
- tauri-prod-release
# This workflow will trigger on each push to the `release` branch to create or update a GitHub release, build your app, and upload the artifacts to the release.
jobs:
publish-tauri:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest' # for Arm based macs (M1 and above).
args: '--target aarch64-apple-darwin'
# - platform: 'macos-latest' # for Intel based macs.
# args: '--target x86_64-apple-darwin'
# - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04.
# args: ''
# - platform: 'windows-latest'
# args: ''
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
# Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
# webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
# You can remove the one that doesn't apply to your app to speed up the workflow a bit.
- name: install frontend dependencies
run: cd ./crates/desktop/tauri-artcraft && yarn install # change this to npm, pnpm or bun depending on which one you use.
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
projectPath: ./crates/desktop/tauri-artcraft
tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
releaseName: 'App v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}
+49 -20
View File
@@ -1,8 +1,50 @@
# TODO TEMP
.env-analytics-job
_develop/tools/101_ip_addresses.txt
_develop/tools/101_user_tokens.txt
api.json
backup_request.sh
dump.sql
dump_report.sql
fixed_request.sh
frontend/.gitignore
frontend/.nx/
frontend/nx
frontend/nx.bat
frontend/nx.json
frontend/package.json
includes/binary_includes/crypto/
island.glb
michael_request.sh
model_weights_titles.txt
output.csv
output.sql
output_smaller.csv
patch.diff
patch.patch
patch2
pubkeys.txt
request.sh
revert-hyper.patch
scratch.txt
select
set
studio-gen-1/
test_data/archive/zip/gptsovits/just_model/
test_data/archive/zip/gptsovits/justin_archive_format/
test_data/temp/
test_data/video/mp4/broken.mp4
test_request_with_sentinel.py
update
users_backup.sql
# Secrets are BAD!
*secret*sh
.env
.env-aichatbot-secrets
.env-analytics-job
.env-elasticsearch-secrets
.env-migration-tool-secrets
.env-secrets
@@ -12,10 +54,15 @@ crates/service/web/storyteller_web/config/storyteller-web.development-secrets.en
db.secrets
db_secrets.toml
env-secrets
pubkeys.txt
production_database_secret_connect.sh
production_database_secret_query.sh
script/production_database_secret_backup.sh
script/production_database_secret_connect.sh
production_database_voice_clone_report_download.sh
secrets.toml
secrets.yaml
twitch_secrets.toml
.DS_Store
# Old env secrets
.*-secrets
@@ -23,26 +70,11 @@ twitch_secrets.toml
# New env secrets (per-app)
*-secrets.env
# Utilities with secrets
script/production_database_secret_backup.sh
script/production_database_secret_connect.sh
production_database_secret_connect.sh
production_database_secret_query.sh
production_database_voice_clone_report_download.sh
# Scratch data
scratch/
test_data/temp/
tmp/
# Rust build directory
target/
crates/lib/database_queries/target/
crates/lib/sqlite_queries/target/
# Javascript build directories
node_modules/
# Vim noise
*.swo
*.swp
@@ -73,9 +105,6 @@ models/tacotron2/python/
# Stuff I want to keep around, but not commit
scraps/
# Mac nonsense
.DS_Store
# Windows build files
# These should be built by the platform
windows/sqlite/sqlite3.exp
-13
View File
@@ -1,13 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="Rust">
<option name="RIGHT_MARGIN" value="180" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="false" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
-5
View File
@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nUPDATE generic_inference_jobs\nSET\n status = \"complete_success\",\n on_success_result_entity_type = ?,\n on_success_result_entity_token = ?,\n failure_reason = NULL,\n internal_debugging_failure_reason = NULL,\n success_execution_millis = ?,\n success_inference_execution_millis = ?,\n retry_at = NULL,\n successfully_completed_at = NOW()\nWHERE token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "2bd7a5b886c9624ae48533ddac409cfca0668f30ab1f7016c412876b5904168b"
}
-6
View File
@@ -1,6 +0,0 @@
{
"files.exclude": {
"**/*~": true,
"frontend_old/**": true
}
}
Generated
+320 -575
View File
File diff suppressed because it is too large Load Diff
+9 -51
View File
@@ -24,7 +24,9 @@ members = [
"crates/cli/production/migration-tool",
# Desktop apps
"crates/desktop/tauri-artcraft",
"crates/desktop/ml_models",
"crates/desktop/ml_weights_registry",
"crates/desktop/tauri-4o",
"crates/desktop/tauri-realtime",
# Shared libraries
@@ -34,12 +36,10 @@ members = [
"crates/lib/api_clients/google_drive_common",
"crates/lib/api_clients/google_sign_in",
"crates/lib/api_clients/openai_sora_client",
"crates/lib/api_clients/storyteller_client",
"crates/lib/api_clients/thumbnail_generator",
"crates/lib/bootstrap",
"crates/lib/bucket_paths",
"crates/lib/caching/memory_caching",
"crates/lib/caching/memory_store",
"crates/lib/caching/redis_caching",
"crates/lib/concurrency",
"crates/lib/cookies",
@@ -65,17 +65,14 @@ members = [
"crates/lib/image_algorithms",
"crates/lib/jobs_common",
"crates/lib/logging",
"crates/lib/machine_learning/ml_models",
"crates/lib/machine_learning/ml_weights_registry",
"crates/lib/machine_learning/prompt_engineering",
"crates/lib/markdown",
"crates/lib/migration",
"crates/lib/mysql_queries",
"crates/lib/password",
"crates/lib/prompt_engineering",
"crates/lib/redis_common",
"crates/lib/redis_schema",
"crates/lib/server_environment",
"crates/lib/shared_service_components",
"crates/lib/sqlx_mysql_helpers",
"crates/lib/storyteller_root",
"crates/lib/subprocess_common",
@@ -118,13 +115,12 @@ members = [
"crates/vendor/candle/candle-transformers",
"crates/vendor/candle/tensor-tools",
"crates/vendor/limitation",
"crates/vendor/tauri-plugin-http",
# NB(bt,2023-12-12): Newrelic keeps breaking with upgrades. Kill for now.
#"crates/vendor/newrelic-telemetry-sdk-rust",
#"crates/vendor/newrelic-telemetry-sdk-rust",
# cargo-hakari workspace hack (compilation speedup hack)
# see usage: https://crates.io/crates/cargo-hakari
"crates/workspace-build-acceleration",
"crates/my-workspace-hack",
]
[workspace.package]
@@ -133,66 +129,28 @@ publish = false
[workspace.dependencies]
# Hakari workspace hack (faster compile times)
#
# If an unrelated leaf package starts causing general build problems,
# for packages including hakari, look up what depends on the bad package:
#
# `cargo tree --target all -p {BAD_PACKAGE_NAME} -i`
#
# Packages to remove from hakari to ensure we can build in Netlify,
# Github Actions (without package installs), etc.:
#
# - cudarc
# - esaxx-rs
# - ort
# - tauri
# - tauri-runtime-wry
# - tauri-utils
#
# Broken on Windows:
# - core-foundation
# - core-foundation-sys
#
workspace-build-acceleration = { path = "crates/workspace-build-acceleration" }
my-workspace-hack = { path = "crates/my-workspace-hack" }
# External libs
# Centrally pinned versions so that we can uniformly upgrade/downgrade versions across the workspace
# If a crate needs to use an older/newer version, the dependency should be managed in that crate's own Cargo.toml
anyhow = "1.0.97"
base64 = "0.22.1"
chrono = { version = "0.4.40", features = ["serde"] }
cookie = "0.18.1"
hex-literal = "1.0.0"
indexmap = "2.9.0"
chrono = "0.4.40"
log = "0.4.27"
once_cell = "1.21.3"
rand = "0.9.0"
regex = "1.11.1"
reqwest = { version = "0.12.15", features = ["json", "cookies"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_derive = "1.0.219"
serde_json = "1.0.140"
serde_yaml = "0.9.1"
sha3 = "0.10.8"
tauri = { version = "2.4.1", features = ["unstable"] }
thiserror = "2.0.12"
toml = "0.8.20"
url = { version = "2.5.4", features = ["serde"] }
toml = "0.7.4"
# Internal libs
crockford = { path = "crates/lib/data/crockford" }
enums = { path = "crates/_types/enums" }
enums_public = { path = "crates/_types/enums_public" }
errors = { path = "crates/lib/errors" }
filesys = { path = "crates/lib/files/filesys" }
idempotency = { path = "crates/lib/idempotency" }
images = { path = "crates/lib/files/images" }
memory_caching = { path = "crates/lib/caching/memory_caching" }
memory_store = { path = "crates/lib/caching/memory_store" }
mimetypes = { path = "crates/lib/files/mimetypes" }
openai_sora_client = { path = "crates/lib/api_clients/openai_sora_client" }
primitives = { path = "crates/lib/data/primitives" }
shared_service_components = { path = "crates/lib/shared_service_components" }
storyteller_client = { path = "crates/lib/api_clients/storyteller_client" }
subprocess_common = { path = "crates/lib/subprocess_common" }
tokens = { path = "crates/_types/tokens" }
@@ -1,6 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
DROP INDEX `index_maybe_creator_anonymous_visitor_token`
ON `generic_inference_jobs`;
@@ -1,7 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs
ADD INDEX index_maybe_creator_anonymous_visitor_token (maybe_creator_anonymous_visitor_token),
ALGORITHM=INPLACE, LOCK=NONE;
@@ -297,7 +297,6 @@ CREATE TABLE generic_inference_jobs (
KEY fk_maybe_input_source_token_and_type (maybe_input_source_token, maybe_input_source_token_type),
KEY fk_on_success_result_entity_token (on_success_result_entity_token),
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
KEY index_maybe_creator_anonymous_visitor_token (maybe_creator_anonymous_visitor_token),
KEY index_creator_ip_address (creator_ip_address),
KEY index_priority_level (priority_level),
KEY index_is_debug_request (is_debug_request),
@@ -13,7 +13,7 @@ name = "composite_identifiers"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -21,7 +21,7 @@ enums = { path = "../enums" }
tokens = { path = "../tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# Serialization
serde = "1.0.125"
+2 -2
View File
@@ -13,13 +13,13 @@ name = "enums"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# Serialization
serde = "1.0.125"
@@ -28,12 +28,11 @@ pub enum MediaFileOriginCategory {
DeviceApi,
/// From Storyteller Studio Engine
#[deprecated(note="This db field should only denote file provenance, not the product.")]
#[serde(rename = "studio")]
StorytellerStudio,
/// From Storyteller Studio Engine
#[deprecated(note = "DO NOT USE. Originally deprecated in favor of `StorytellerStudio`.")]
#[deprecated(note = "Use StorytellerStudio instead")]
StoryEngine,
}
@@ -57,9 +57,6 @@ pub enum MediaFileOriginModelType {
#[serde(rename = "studio")]
StorytellerStudio,
#[serde(rename = "studio_ig")]
StorytellerStudioImageGen,
#[serde(rename = "vst")]
VideoStyleTransfer,
@@ -96,7 +93,6 @@ impl MediaFileOriginModelType {
Self::MocapNet => "mocap_net",
Self::StyleTTS2 => "styletts2",
Self::StableDiffusion15 => "stable_diffusion_1_5",
Self::StorytellerStudioImageGen => "studio_ig",
Self::GptSovits => "gpt_sovits",
Self::StorytellerStudio => "studio",
Self::VideoStyleTransfer => "vst",
@@ -119,7 +115,6 @@ impl MediaFileOriginModelType {
"mocap_net" => Ok(Self::MocapNet),
"styletts2" => Ok(Self::StyleTTS2),
"stable_diffusion_1_5" => Ok(Self::StableDiffusion15),
"studio_ig" => Ok(Self::StorytellerStudioImageGen),
"gpt_sovits" => Ok(Self::GptSovits),
"studio" => Ok(Self::StorytellerStudio),
"vst" => Ok(Self::VideoStyleTransfer),
@@ -147,7 +142,6 @@ impl MediaFileOriginModelType {
Self::StableDiffusion15,
Self::GptSovits,
Self::StorytellerStudio,
Self::StorytellerStudioImageGen,
Self::VideoStyleTransfer,
Self::ComfyUi,
Self::VallEX,
@@ -39,10 +39,6 @@ pub enum MediaFileOriginProductCategory {
#[serde(rename = "vst")]
VideoStyleTransfer,
/// Image Studio
#[serde(rename = "image_studio")]
ImageStudio,
/// Storyteller Studio
#[serde(rename = "studio")]
StorytellerStudio,
@@ -91,7 +87,6 @@ impl MediaFileOriginProductCategory {
Self::FaceFusion => "face_fusion",
Self::FaceMirror => "face_mirror",
Self::VideoStyleTransfer => "vst",
Self::ImageStudio => "image_studio",
Self::StorytellerStudio => "studio",
Self::TextToSpeech => "tts",
Self::VoiceConversion => "voice_conversion",
@@ -110,7 +105,6 @@ impl MediaFileOriginProductCategory {
"face_fusion" => Ok(Self::FaceFusion),
"face_mirror" => Ok(Self::FaceMirror),
"vst" => Ok(Self::VideoStyleTransfer),
"image_studio" => Ok(Self::ImageStudio),
"studio" => Ok(Self::StorytellerStudio),
"tts" => Ok(Self::TextToSpeech),
"voice_conversion" => Ok(Self::VoiceConversion),
@@ -132,7 +126,6 @@ impl MediaFileOriginProductCategory {
Self::FaceFusion,
Self::FaceMirror,
Self::VideoStyleTransfer,
Self::ImageStudio,
Self::StorytellerStudio,
Self::TextToSpeech,
Self::VoiceConversion,
@@ -160,7 +153,6 @@ mod tests {
assert_serialization(MediaFileOriginProductCategory::FaceFusion, "face_fusion");
assert_serialization(MediaFileOriginProductCategory::FaceMirror, "face_mirror");
assert_serialization(MediaFileOriginProductCategory::VideoStyleTransfer, "vst");
assert_serialization(MediaFileOriginProductCategory::ImageStudio, "image_studio");
assert_serialization(MediaFileOriginProductCategory::StorytellerStudio, "studio");
assert_serialization(MediaFileOriginProductCategory::TextToSpeech, "tts");
assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion");
@@ -178,7 +170,6 @@ mod tests {
assert_eq!(MediaFileOriginProductCategory::FaceFusion.to_str(), "face_fusion");
assert_eq!(MediaFileOriginProductCategory::FaceMirror.to_str(), "face_mirror");
assert_eq!(MediaFileOriginProductCategory::VideoStyleTransfer.to_str(), "vst");
assert_eq!(MediaFileOriginProductCategory::ImageStudio.to_str(), "image_studio");
assert_eq!(MediaFileOriginProductCategory::StorytellerStudio.to_str(), "studio");
assert_eq!(MediaFileOriginProductCategory::TextToSpeech.to_str(), "tts");
assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion");
@@ -196,7 +187,6 @@ mod tests {
assert_eq!(MediaFileOriginProductCategory::from_str("face_fusion").unwrap(), MediaFileOriginProductCategory::FaceFusion);
assert_eq!(MediaFileOriginProductCategory::from_str("face_mirror").unwrap(), MediaFileOriginProductCategory::FaceMirror);
assert_eq!(MediaFileOriginProductCategory::from_str("vst").unwrap(), MediaFileOriginProductCategory::VideoStyleTransfer);
assert_eq!(MediaFileOriginProductCategory::from_str("image_studio").unwrap(), MediaFileOriginProductCategory::ImageStudio);
assert_eq!(MediaFileOriginProductCategory::from_str("studio").unwrap(), MediaFileOriginProductCategory::StorytellerStudio);
assert_eq!(MediaFileOriginProductCategory::from_str("tts").unwrap(), MediaFileOriginProductCategory::TextToSpeech);
assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion);
@@ -210,13 +200,12 @@ mod tests {
#[test]
fn all_variants() {
let mut variants = MediaFileOriginProductCategory::all_variants();
assert_eq!(variants.len(), 14);
assert_eq!(variants.len(), 13);
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceAnimator));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceFusion));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceMirror));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VideoStyleTransfer));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ImageStudio));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::StorytellerStudio));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::TextToSpeech));
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion));
+2 -2
View File
@@ -13,11 +13,11 @@ name = "enums_public"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# Internal
enums = { path = "../enums" }
@@ -64,10 +64,6 @@ pub enum PublicMediaFileModelType {
#[serde(rename = "studio")]
StorytellerStudio,
/// NB: This is GPT4o image generation
#[serde(rename = "studio_ig")]
StorytellerStudioImageGen,
#[serde(rename = "vst")]
VideoStyleTransfer,
@@ -93,7 +89,6 @@ impl PublicMediaFileModelType {
MediaFileOriginModelType::LivePortrait => Self::FaceMirror,
MediaFileOriginModelType::SadTalker => Self::FaceAnimator,
MediaFileOriginModelType::StyleTTS2 => Self::VoiceDesigner,
MediaFileOriginModelType::StorytellerStudioImageGen => Self::StorytellerStudioImageGen,
// Conserved variants
MediaFileOriginModelType::RvcV2 => Self::RvcV2,
MediaFileOriginModelType::SoVitsSvc => Self::SoVitsSvc,
@@ -118,7 +113,6 @@ impl PublicMediaFileModelType {
Self::FaceAnimator => MediaFileOriginModelType::SadTalker,
Self::Lipsync => MediaFileOriginModelType::FaceFusion,
Self::VoiceDesigner => MediaFileOriginModelType::StyleTTS2,
Self::StorytellerStudioImageGen => MediaFileOriginModelType::StorytellerStudioImageGen,
// Conserved variants
Self::RvcV2 => MediaFileOriginModelType::RvcV2,
Self::SoVitsSvc => MediaFileOriginModelType::SoVitsSvc,
+2 -2
View File
@@ -13,7 +13,7 @@ name = "reusable_types"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
@@ -21,7 +21,7 @@ normal = ["workspace-build-acceleration"]
# (none)
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# External
chrono = { version = "0.4.22", features = ["serde"] }
+2 -2
View File
@@ -13,7 +13,7 @@ name = "tokens"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
@@ -21,7 +21,7 @@ normal = ["workspace-build-acceleration"]
# (none)
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# Serialization
serde = "1.0.125"
@@ -13,7 +13,7 @@ name = "dev-database-seed"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -32,7 +32,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
log = "0.4.14"
@@ -13,7 +13,7 @@ name = "dev-upload-media-file"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -29,7 +29,7 @@ mysql_queries = { path = "../../../lib/mysql_queries" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = "4.4.8"
+2 -2
View File
@@ -13,7 +13,7 @@ name = "scrape-test"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
@@ -22,7 +22,7 @@ errors = { path = "../../../lib/errors" }
web_scrapers = { path = "../../../lib/web_scrapers" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = "4.4.8"
+2 -2
View File
@@ -13,11 +13,11 @@ name = "db-backfill"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# Internal
datetimes = { path = "../../../lib/data/datetimes" }
+2 -2
View File
@@ -13,7 +13,7 @@ name = "db-backup"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -21,7 +21,7 @@ easyenv = { path = "../../../lib/easyenv" }
errors = { path = "../../../lib/errors" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
anyhow = "1.0.86"
+2 -2
View File
@@ -13,7 +13,7 @@ name = "db-cleanup"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -26,7 +26,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = "4.4.8"
@@ -13,7 +13,7 @@ name = "elasticsearch-cli"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -29,7 +29,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = "4.4.8"
@@ -13,7 +13,7 @@ name = "kubectl-pod-cleanup"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -22,7 +22,7 @@ easyenv = { path = "../../../lib/easyenv" }
errors = { path = "../../../lib/errors" }
# Workspace hack (faster compile yytimes)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
log = "0.4.20"
@@ -13,7 +13,7 @@ name = "lru-delete-models"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -21,7 +21,7 @@ errors = { path = "../../../lib/errors" }
logging = { path = "../../../lib/logging" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = { version = "4.4.8", features = ["derive"] }
@@ -13,7 +13,7 @@ name = "migration-tool"
path = "src/main.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Internal
@@ -30,7 +30,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
clap = "4.4.8"
@@ -14,19 +14,16 @@ path = "src/lib.rs"
crate-type = ["staticlib", "cdylib", "rlib"]
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
normal = ["my-workspace-hack"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
filesys = { path = "../../files/filesys" }
image_algorithms = { path = "../../image_algorithms" }
memory_caching = { path = "../../caching/memory_caching" }
filesys = { path = "../../lib/files/filesys" }
image_algorithms = { path = "../../lib/image_algorithms" }
memory_caching = { path = "../../lib/caching/memory_caching" }
ml_weights_registry = { path = "../ml_weights_registry" }
primitives = { path = "../../data/primitives" }
primitives = { path = "../../lib/data/primitives" }
# Bypass cudarc issues on Windows https://github.com/coreylowman/cudarc/issues/332
cudarc = "0.13.7"
@@ -35,9 +32,9 @@ cudarc = "0.13.7"
anyhow = "1.0"
base64 = "0.22.1"
bytes = "1.10"
candle-core = { path = "../../../vendor/candle/candle-core", features = ["cuda"] }
candle-nn = { path = "../../../vendor/candle/candle-nn", features = ["cuda"] }
candle-transformers = { path = "../../../vendor/candle/candle-transformers", features = ["cuda"] }
candle-core = { path = "../../vendor/candle/candle-core", features = ["cuda"] }
candle-nn = { path = "../../vendor/candle/candle-nn", features = ["cuda"] }
candle-transformers = { path = "../../vendor/candle/candle-transformers", features = ["cuda"] }
const_format = "0.2.34"
directories = "6.0.0"
dirs = "6.0.0"
@@ -1,5 +1,5 @@
[package]
name = "tauri-artcraft"
name = "artcraft"
version = "0.1.0"
description = "Artcraft"
authors = ["you"]
@@ -12,7 +12,7 @@ publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "tauri_artcraft_app_lib"
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
@@ -20,23 +20,22 @@ tauri-build = { version = "2.1.1", features = [] }
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
my-workspace-hack = { workspace = true }
# Internal
crockford = { workspace = true }
errors = { workspace = true }
filesys = { workspace = true }
memory_caching = { workspace = true }
memory_store = { workspace = true }
openai_sora_client = { workspace = true }
primitives = { workspace = true }
storyteller_client = { workspace = true }
subprocess_common = { workspace = true }
tokens = { workspace = true }
# External
#openssl = { version = "0.10", features = ["vendored"] }
# NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
anyhow = { workspace = true }
base64 = { workspace = true }
base64 = "0.22.1"
bytes = "1.10"
chrono = { workspace = true }
const_format = "0.2.34"
@@ -44,29 +43,21 @@ directories = "6.0.0"
dirs = "6.0.0"
futures = "0.3"
image = "0.25.5"
indexmap = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true, features = ["multipart", "stream"], default-features = false } # NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
reqwest = { workspace = true, features = ["multipart", "stream"], default-features = false }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
tauri = { workspace = true }
tauri = { version = "2.4.1", features = ["unstable"] }
tauri-plugin-log = "2.3.1"
tempdir = "0.3.7"
tempfile = "3.18.0"
tokio = { version = "1.42", features = ["rt", "rt-multi-thread", "fs"] }
tokio-util = { version = "0.7", features = ["codec"] }
# NB: We need to vendor this in so that we can access the cookies inside via the private API
tauri-plugin-http = { path = "../../vendor/tauri-plugin-http" }
# NB: The version of the `discord-rich-presence` crate (0.2.5) last published has non-Send/Sync error
# types and can't do threading. We need to wait for a new version to unpin from Git.
discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence" }
[dev-dependencies]
libloading = "0.8.6"
serial_test = "3.2.0"
@@ -0,0 +1,12 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "enables the default permissions",
"windows": [
"main"
],
"permissions": [
"core:default",
"log:default"
]
}

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

@@ -0,0 +1,90 @@
use std::fs::read_to_string;
use base64::prelude::BASE64_STANDARD;
use errors::AnyhowResult;
use base64::Engine;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{DynamicImage, ImageReader};
use std::io::Cursor;
use log::{error, info};
use tauri::{AppHandle, Manager, State};
use openai_sora_client::credentials::SoraCredentials;
use openai_sora_client::image_gen::common::{ImageSize, NumImages};
use openai_sora_client::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
use openai_sora_client::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
use openai_sora_client::upload::upload_media_from_file::SoraMediaUploadRequest;
use crate::state::app_dir::AppDataRoot;
#[tauri::command]
pub async fn image_generation_command(
image: &str,
prompt: &str,
app: AppHandle,
app_data_root: State<'_, AppDataRoot>,
) -> Result<String, String> {
info!("image_generation_command called; processing image...");
let bytes = BASE64_STANDARD.decode(image)
.map_err(|err| format!("Base64 decode error: {}", err))?;
generate_image(bytes, prompt, &app_data_root)
.await
.map_err(|err| {
error!("error: {:?}", err);
"there was an error".to_string()
})?;
Ok("success".to_string())
}
pub async fn generate_image(file_bytes: Vec<u8>, prompt: &str, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
let sora_credentials = get_credentials(app_data_root)?;
let filename = "image.png".to_string();
let response= sora_media_upload_from_bytes(file_bytes, filename, &sora_credentials)
.await
.map_err(|err| {
error!("Failed to upload image to Sora: {:?}", err);
err
})?;
let sora_media_tokens = vec![response.id];
let response = sora_image_gen_remix(SoraImageGenRemixRequest {
prompt: prompt.to_string(),
num_images: NumImages::One,
image_size: ImageSize::Square,
sora_media_tokens: sora_media_tokens.clone(),
credentials: &sora_credentials,
}).await
.map_err(|err| {
error!("Failed to call Sora image generation: {:?}", err);
err
})?;
println!(">> TASK ID: {:?} ", response.task_id);
Ok(())
}
fn get_credentials(app_data_root: &AppDataRoot) -> AnyhowResult<SoraCredentials> {
let cookie_file = app_data_root.get_sora_cookie_file_path();
let bearer = read_to_string("/Users/bt/dev/storyteller/storyteller-rust/test_data/temp/bearer.txt")?
.trim()
.to_string();
let cookie= read_to_string(cookie_file)?
.trim()
.to_string();
let sentinel = read_to_string("/Users/bt/dev/storyteller/storyteller-rust/test_data/temp/sentinel.txt")?
.trim()
.to_string();
Ok(SoraCredentials {
bearer_token: bearer,
cookie: cookie,
sentinel: Some(sentinel),
})
}
@@ -0,0 +1,3 @@
pub mod flip_image;
pub mod image_generation_command;
pub mod open_login_command;
@@ -1,11 +1,11 @@
use crate::threads::sora_session_login_thread::{LOGIN_WINDOW_NAME, SORA_LOGIN_URL};
use crate::utils::clear_all_webview_cookies::clear_all_webview_cookies;
use errors::AnyhowResult;
use std::time::Duration;
use log::{error, info};
use once_cell::sync::Lazy;
use std::time::Duration;
use tauri::{AppHandle, Manager, Url, WebviewUrl, WebviewWindowBuilder, WindowBuilder};
use tokio::time::sleep_until;
use errors::AnyhowResult;
use crate::threads::login_thread::{LOGIN_WINDOW_NAME, SORA_LOGIN_URL};
use crate::utils::clear_all_webview_cookies::clear_all_webview_cookies;
pub const START_URL_STR: &str = "https://storyteller.ai/";
@@ -20,7 +20,7 @@ pub static SORA_HOMEPAGE_URL : Lazy<Url> = Lazy::new(|| {
});
#[tauri::command]
pub async fn open_sora_login_command(
pub async fn open_login_command(
app: AppHandle,
) -> Result<String, String> {
info!("open_login_command called");
+65
View File
@@ -0,0 +1,65 @@
pub mod commands;
pub mod events;
pub mod state;
pub mod threads;
pub mod transfer;
pub mod utils;
use crate::commands::flip_image::flip_image;
use crate::commands::image_generation_command::image_generation_command;
use crate::commands::open_login_command::open_login_command;
use crate::state::app_config::AppConfig;
use crate::threads::login_thread::login_thread;
use tauri_plugin_log::Target;
use tauri_plugin_log::TargetKind;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
// NB: Tauri wants to install the logger itself, so we can't rely on the logger crate
// until the tauri runtime begins.
println!("Loading model config...");
let config = AppConfig::init()
.expect("config should load");
let app_data_root = config.app_data_root.clone();
let app_data_root2 = config.app_data_root.clone();
println!("Initializing backend runtime...");
tauri::Builder::default()
.plugin(tauri_plugin_log::Builder::new()
.level(log::LevelFilter::Info)
.targets(vec![
Target::new(TargetKind::Stdout),
Target::new(TargetKind::LogDir { file_name: Some(app_data_root.log_file_name_str().to_string()) }),
])
.build())
.setup(|app| {
// TODO(bt): This is broken on windows
// log_environment_details();
//if cfg!(debug_assertions) {
// app.handle().plugin(
// tauri_plugin_log::Builder::default()
// .level(log::LevelFilter::Info)
// .build(),
// )?;
//}
let app = app.handle().clone();
tauri::async_runtime::spawn(login_thread(app, app_data_root2));
Ok(())
})
.manage(config)
.manage(app_data_root)
.invoke_handler(tauri::generate_handler![
flip_image,
image_generation_command,
open_login_command,
])
.run(tauri::generate_context!("tauri.conf.json"))
.expect("error while running tauri application");
}
@@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
tauri_artcraft_app_lib::run();
app_lib::run();
}
@@ -1,4 +1,4 @@
use crate::state::data_dir::app_data_root::AppDataRoot;
use crate::state::app_dir::AppDataRoot;
use crate::state::os_platform::OsPlatform;
use crate::state::yaml_config::YamlConfig;
@@ -0,0 +1,219 @@
use crate::state::expanduser::expanduser;
use crate::state::os_platform::OsPlatform;
use anyhow::anyhow;
use directories::UserDirs;
use std::path::{Path, PathBuf};
use chrono::{DateTime, Local};
use tempdir::TempDir;
use tempfile::{Builder, NamedTempFile};
const DEFAULT_DATA_DIR : &str = "artcraft";
const ASSETS_SUBDIRECTORY : &str = "assets";
const WEIGHTS_SUBDIRECTORY : &str = "weights";
const TEMPORARY_SUBDIRECTORY : &str = "temp";
/// Note: Tauri appends ".log" to the end of the filename.
const LOG_FILE_NAME : &str = "application_debug";
/// The path to the application data directory, which includes "asset" and "weights" data.
#[derive(Clone)]
pub struct AppDataRoot {
path: PathBuf,
assets_dir: AppAssetsDir,
weights_dir: AppWeightsDir,
temp_dir: TemporaryDir,
log_file_name: PathBuf,
log_file_name_string: String,
}
#[derive(Clone)]
pub struct AppAssetsDir {
path: PathBuf,
}
#[derive(Clone)]
pub struct AppWeightsDir {
path: PathBuf,
}
#[derive(Clone)]
pub struct TemporaryDir {
path: PathBuf,
}
impl AppDataRoot {
pub fn create_default() -> anyhow::Result<Self> {
let directory = get_default_data_dir()?;
Self::create_existing(directory)
}
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
let mut dir = dir.as_ref().to_path_buf();
match OsPlatform::get() {
OsPlatform::Linux | OsPlatform::MacOs => {
if let Some(d) = dir.as_os_str().to_str() {
dir = expanduser(d)?;
}
},
OsPlatform::Windows => {}
}
if !dir.is_dir() {
println!("Creating directory {:?}", dir);
std::fs::create_dir_all(&dir)?;
}
match dir.canonicalize() {
Ok(d) => dir = d,
Err(err) => {
println!("Error canonicalizing {:?}: {}", dir, err);
}
}
let assets_dir = AppAssetsDir::create_existing(dir.join(ASSETS_SUBDIRECTORY))?;
let weights_dir = AppWeightsDir::create_existing(dir.join(WEIGHTS_SUBDIRECTORY))?;
let temp_dir = TemporaryDir::create_existing(dir.join(TEMPORARY_SUBDIRECTORY))?;
let log_file_name = dir.join(LOG_FILE_NAME);
let log_file_name_string = log_file_name
.to_str()
.ok_or(anyhow!("couldn't convert log path to str"))?
.to_string();
Ok(Self {
path: dir,
assets_dir,
weights_dir,
temp_dir,
log_file_name,
log_file_name_string,
})
}
pub fn assets_dir(&self) -> &AppAssetsDir {
&self.assets_dir
}
pub fn weights_dir(&self) -> &AppWeightsDir {
&self.weights_dir
}
pub fn temp_dir(&self) -> &TemporaryDir {
&self.temp_dir
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn log_file_name(&self) -> &Path {
&self.log_file_name
}
pub fn log_file_name_str(&self) -> &str {
&self.log_file_name_string
}
pub fn get_sora_cookie_file_path(&self) -> PathBuf {
self.path.join("sora_cookies.txt")
}
}
impl AppAssetsDir {
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
let mut dir = dir.as_ref().to_path_buf();
match dir.canonicalize() {
Ok(d) => dir = d,
Err(err) => {
println!("Error canonicalizing {:?}: {}", dir, err);
}
}
if !dir.exists() {
println!("Creating directory {:?}", dir);
std::fs::create_dir(&dir)?;
}
Ok(Self {
path: dir,
})
}
pub fn path(&self) -> &Path {
&self.path
}
/// Return the current date asset directory
/// If it doesn't exist, create it.
pub fn make_or_get_current_date_dir(&self) -> anyhow::Result<PathBuf> {
let format: DateTime<Local> = Local::now();
let date_directory_name = format.format("%Y-%d-%m").to_string();
let full_path = self.path.join(date_directory_name);
if !full_path.exists() {
std::fs::create_dir(&full_path)?;
}
Ok(full_path)
}
}
impl AppWeightsDir {
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
let mut dir = dir.as_ref().to_path_buf();
match dir.canonicalize() {
Ok(d) => dir = d,
Err(err) => {
println!("Error canonicalizing {:?}: {}", dir, err);
}
}
if !dir.exists() {
println!("Creating directory {:?}", dir);
std::fs::create_dir(&dir)?;
}
Ok(Self {
path: dir,
})
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl TemporaryDir {
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
let mut dir = dir.as_ref().to_path_buf();
match dir.canonicalize() {
Ok(d) => dir = d,
Err(err) => {
println!("Error canonicalizing {:?}: {}", dir, err);
}
}
if !dir.exists() {
println!("Creating directory {:?}", dir);
std::fs::create_dir(&dir)?;
}
Ok(Self {
path: dir,
})
}
pub fn with_prefix(&self, prefix: &str) -> anyhow::Result<TempDir> {
let tempdir = TempDir::new_in(&self.path, prefix)?;
Ok(tempdir)
}
pub fn new_named_temp_file(&self) -> anyhow::Result<NamedTempFile> {
let tempfile = Builder::new()
.prefix("temp_")
.suffix(".bin")
.tempfile_in(&self.path)?;
Ok(tempfile)
}
}
// eg. /home/bob/artcraft, /Users/bob/artcraft, or C:\Users\Alice\artcraft
fn get_default_data_dir() -> anyhow::Result<PathBuf> {
Ok(UserDirs::new()
.ok_or_else(|| anyhow!("could not determine user home directory"))?
.home_dir()
.join(DEFAULT_DATA_DIR))
}
+5
View File
@@ -0,0 +1,5 @@
pub mod app_config;
pub mod app_dir;
pub mod os_platform;
pub mod yaml_config;
pub mod expanduser;
@@ -0,0 +1,20 @@
#[derive(Copy,Clone,Eq,PartialEq,Debug)]
pub enum OsPlatform {
Linux,
MacOs,
Windows,
}
impl OsPlatform {
pub fn get() -> OsPlatform {
// Totally scientific.
// https://doc.rust-lang.org/std/env/consts/constant.OS.html
match std::env::consts::OS {
"linux" => OsPlatform::Linux,
"windows" => OsPlatform::Windows,
"macos" | "apple" => OsPlatform::MacOs,
_ => OsPlatform::Linux,
}
}
}
@@ -0,0 +1,103 @@
use std::fs::OpenOptions;
use std::io::Write;
use anyhow::anyhow;
use log::{error, info};
use once_cell::sync::Lazy;
use reqwest::Url;
use tauri::{AppHandle, Manager, Webview};
use errors::AnyhowResult;
use crate::state::app_dir::AppDataRoot;
use crate::utils::sora_webview_cookies::get_all_sora_cookies_as_string;
pub const LOGIN_WINDOW_NAME: &str = "login_window";
pub const SORA_LOGIN_URL_STR: &str = "https://sora.com/auth/login?callback_path=/";
pub static SORA_LOGIN_URL: Lazy<Url> = Lazy::new(|| {
Url::parse(SORA_LOGIN_URL_STR).expect("URL should parse")
});
pub const SORA_ROOT_URL_STR: &str = "https://sora.com/";
pub static SORA_ROOT_URL: Lazy<Url> = Lazy::new(|| {
Url::parse(SORA_ROOT_URL_STR).expect("URL should parse")
});
pub async fn login_thread(app: AppHandle, app_data_root: AppDataRoot) -> ! {
loop {
for (window_name, webview) in app.webviews() {
if window_name == LOGIN_WINDOW_NAME {
let result = check_login_window(&webview, &app_data_root).await;
if let Err(err) = result {
error!("Error checking login window: {:?}", err);
}
break;
}
}
tokio::time::sleep(std::time::Duration::from_millis(2_000)).await;
}
}
async fn check_login_window(webview: &Webview, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
clear_browsing_data_on_test_domain(webview)?;
//keep_on_task(webview)?;
extract_cookies_to_file(webview, app_data_root)?;
// TODO: Other maintenance tasks ...
Ok(())
}
fn keep_on_task(webview: &Webview) -> AnyhowResult<()> {
let url = webview.url()?;
let hostname= url.host()
.ok_or(anyhow!("no host in url"))?
.to_string();
match hostname.as_str() {
"auth.openai.com" => {},
"openai.com" => {},
"sora.com" => {},
// Third party SSO
"accounts.google.com" => {},
"accounts.youtube.com" => {},
"login.live.com" => {},
"appleid.apple.com" => {},
_ => {
info!("Non login hostname: {}", hostname);
webview.navigate(SORA_LOGIN_URL.clone())?;
}
}
Ok(())
}
/// This is just so we have a way to clear browsing data.
fn clear_browsing_data_on_test_domain(webview: &Webview) -> AnyhowResult<()> {
let url = webview.url()?;
let hostname= url.host()
.ok_or(anyhow!("no host in url"))?
.to_string();
match hostname.as_str() {
"storyteller.ai" => {
info!("Clearing all browsing data...");
webview.clear_all_browsing_data()?;
}
_ => {}
}
Ok(())
}
// TODO(bt,2025-04-07): Heuristic to detect when logged in. Only write when logged in.
fn extract_cookies_to_file(webview: &Webview, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
let cookies = get_all_sora_cookies_as_string(webview)?;
let cookie_file = app_data_root.get_sora_cookie_file_path();
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(cookie_file)?;
file.write_all(cookies.as_bytes())?;
file.flush()?;
Ok(())
}
@@ -0,0 +1 @@
pub mod login_thread;
@@ -1,10 +1,9 @@
//! Implemented from https://github.com/huggingface/hf_transfer/blob/main/src/lib.rs
use crate::utils::large_file_transfer::error::Error;
use crate::utils::large_file_transfer::util::{exponential_backoff, BASE_WAIT_TIME, MAX_WAIT_TIME};
use crate::transfer::error::Error;
use crate::transfer::util::{exponential_backoff, BASE_WAIT_TIME, MAX_WAIT_TIME};
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use log::info;
use reqwest::header::{
HeaderMap, HeaderName, HeaderValue, AUTHORIZATION, CONTENT_RANGE,
RANGE,
@@ -15,14 +14,15 @@ use std::fmt::Display;
use std::fs::remove_file;
use std::io::SeekFrom;
use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::time::Duration;
use log::info;
use tempfile::NamedTempFile;
use tokio::fs::OpenOptions;
use tokio::io::AsyncSeekExt;
use tokio::io::AsyncWriteExt;
use tokio::io::AsyncSeekExt;
use tokio::sync::Semaphore;
use tokio::time::sleep;

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