mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-27 12:10:08 -04:00
Compare commits
65
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
398c56d7eb | ||
|
|
ba21368323 | ||
|
|
0750b9fe10 | ||
|
|
05a26b124e | ||
|
|
a394ee5a96 | ||
|
|
c35ea620b3 | ||
|
|
389b1c3d17 | ||
|
|
f9148d3cf6 | ||
|
|
64d66aa9f0 | ||
|
|
82695725cd | ||
|
|
53f9032603 | ||
|
|
69c03045fd | ||
|
|
e82f070d1d | ||
|
|
459960e64f | ||
|
|
d1266b7591 | ||
|
|
4bdb1c89a4 | ||
|
|
4d53d9af18 | ||
|
|
2bc00d7f80 | ||
|
|
f48cb41f21 | ||
|
|
d24508aee9 | ||
|
|
1985d9acd7 | ||
|
|
0f90981f30 | ||
|
|
8d1ca743db | ||
|
|
72403ad4d8 | ||
|
|
8d731f1155 | ||
|
|
516d740e97 | ||
|
|
95eeafd6f0 | ||
|
|
0db5646deb | ||
|
|
ac839e2c39 | ||
|
|
65334e12be | ||
|
|
7e644c3e98 | ||
|
|
bb3fe2df2d | ||
|
|
a92ad2eb3a | ||
|
|
78e7d08f04 | ||
|
|
be18036bf6 | ||
|
|
83a8852cef | ||
|
|
afed8688a5 | ||
|
|
9d380decf9 | ||
|
|
4905cdcd3d | ||
|
|
b709b6e764 | ||
|
|
58d2665f0e | ||
|
|
72bf6738e1 | ||
|
|
1178bb7ebf | ||
|
|
fea20c417c | ||
|
|
5a07903870 | ||
|
|
2063434304 | ||
|
|
b386fd5d88 | ||
|
|
1626dda8b4 | ||
|
|
ebe365703b | ||
|
|
5caa578b86 | ||
|
|
2da5fbcc58 | ||
|
|
588650b1b5 | ||
|
|
761bf832a5 | ||
|
|
df4d46cc9d | ||
|
|
19599e00be | ||
|
|
2f2ac350bc | ||
|
|
bbd0871c04 | ||
|
|
7d20ac3d16 | ||
|
|
f9c1201fc6 | ||
|
|
0ac57a5448 | ||
|
|
b88f5c536b | ||
|
|
7edba0d9d5 | ||
|
|
76ae56a051 | ||
|
|
75a92fe204 | ||
|
|
31c507a404 |
@@ -10,6 +10,20 @@ on:
|
||||
#- $default-branch
|
||||
- main
|
||||
- test
|
||||
# Only build when files that affect the Docker image change.
|
||||
# This avoids expensive 15-25 min builds for docs-only or config-only changes.
|
||||
paths:
|
||||
# Individual files
|
||||
- '.github/workflows/docker-publish-cpu.yml'
|
||||
- 'Cargo.lock'
|
||||
- 'Cargo.toml'
|
||||
- 'build/service_cpu.Dockerfile'
|
||||
# Directories
|
||||
- '.sqlx/**'
|
||||
- '_database/**'
|
||||
- 'crates/**'
|
||||
- 'includes/**'
|
||||
- 'test_data/**'
|
||||
env:
|
||||
IMAGE_NAME: storyteller-rust
|
||||
|
||||
|
||||
+2
-1
@@ -36,8 +36,9 @@ script/socat_dev_database_connect.sh
|
||||
# Python virtual envs (named by convention)
|
||||
venv/
|
||||
|
||||
# Testing
|
||||
# LLM Testing
|
||||
/prompts/
|
||||
/reports/
|
||||
/requests/
|
||||
|
||||
# Scratch data
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO prompts\nSET\n token = ?,\n prompt_type = ?,\n\n maybe_creator_user_token = ?,\n \n maybe_model_type = ?,\n maybe_generation_provider = ?,\n\n maybe_positive_prompt = ?,\n maybe_negative_prompt = ?,\n \n maybe_other_args = ?,\n\n creator_ip_address = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 9
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "08f52f15acf6afc7091a525e3dc88f706c71c3579e5e81aa9903807d85f469ef"
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n u.id as `id: u64`,\n u.token as `token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name,\n u.username_is_not_customized as `username_is_not_customized: bool`,\n u.email_address,\n u.email_confirmed as `email_confirmed: bool`,\n u.is_without_password as `is_without_password: bool`,\n u.ip_address_creation,\n u.maybe_source as `maybe_source: enums::by_table::users::user_signup_source::UserSignupSource`,\n u.maybe_signup_method as `maybe_signup_method: enums::by_table::users::user_signup_method::UserSignupMethod`,\n u.created_at,\n u.maybe_referral_url,\n u.is_temporary as `is_temporary: bool`\nFROM users AS u\nWHERE\n u.id < ?\n AND u.user_deleted_at IS NULL\n AND u.mod_deleted_at IS NULL\nORDER BY u.id DESC\nLIMIT ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id: u64",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT",
|
||||
"char_set": 63,
|
||||
"max_size": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "username_is_not_customized: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "email_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email_confirmed: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "is_without_password: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "ip_address_creation",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "maybe_source: enums::by_table::users::user_signup_source::UserSignupSource",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_signup_method: enums::by_table::users::user_signup_method::UserSignupMethod",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "maybe_referral_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "is_temporary: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "2fe10ae5a2d013e1861f71dcb0afae4048e0d47c5b584c6bbc7df25dde747e87"
|
||||
}
|
||||
+71
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n p.token as `token: tokens::tokens::prompts::PromptToken`,\n\n p.prompt_type as `prompt_type: enums::by_table::prompts::prompt_type::PromptType`,\n\n p.maybe_model_type as `maybe_model_type: enums::common::model_type::ModelType`,\n p.maybe_generation_provider as `maybe_generation_provider: enums::common::generation_provider::GenerationProvider`,\n\n p.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n\n p.maybe_positive_prompt,\n p.maybe_negative_prompt,\n p.maybe_other_args,\n\n p.creator_ip_address,\n p.created_at\n\nFROM prompts as p\nWHERE\n p.token = ?\n ",
|
||||
"query": "\nSELECT\n p.token as `token: tokens::tokens::prompts::PromptToken`,\n\n p.prompt_type as `prompt_type: enums::by_table::prompts::prompt_type::PromptType`,\n\n p.maybe_model_type as `maybe_model_type: enums::common::generation::common_model_type::CommonModelType`,\n p.maybe_generation_provider as `maybe_generation_provider: enums::common::generation_provider::GenerationProvider`,\n\n p.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n\n p.maybe_positive_prompt,\n p.maybe_negative_prompt,\n\n p.maybe_generation_mode as `maybe_generation_mode: enums::common::generation::common_generation_mode::CommonGenerationMode`,\n p.maybe_aspect_ratio as `maybe_aspect_ratio: enums::common::generation::common_aspect_ratio::CommonAspectRatio`,\n p.maybe_resolution as `maybe_resolution: enums::common::generation::common_resolution::CommonResolution`,\n p.maybe_batch_count as `maybe_batch_count: u8`,\n p.maybe_generate_audio as `maybe_generate_audio: bool`,\n p.maybe_duration_seconds as `maybe_duration_seconds: u32`,\n\n p.maybe_other_args,\n\n p.creator_ip_address,\n p.created_at\n\nFROM prompts as p\nWHERE\n p.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "maybe_model_type: enums::common::model_type::ModelType",
|
||||
"name": "maybe_model_type: enums::common::generation::common_model_type::CommonModelType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
@@ -75,6 +75,66 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "maybe_generation_mode: enums::common::generation::common_generation_mode::CommonGenerationMode",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 96
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "maybe_aspect_ratio: enums::common::generation::common_aspect_ratio::CommonAspectRatio",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 96
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "maybe_resolution: enums::common::generation::common_resolution::CommonResolution",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_batch_count: u8",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "maybe_generate_audio: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "maybe_duration_seconds: u32",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "maybe_other_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -84,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 14,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 15,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -116,9 +176,15 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b46b0d022790f4e10f6e47126df0fdc55172bf8cda77d4e0b2afac9e6ebd1630"
|
||||
"hash": "4a50b7bf06061f05e769a41e547cb927bd2b3a6f67c8ceb37883b744237ba34c"
|
||||
}
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n u.id as `id: u64`,\n u.token as `token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name,\n u.username_is_not_customized as `username_is_not_customized: bool`,\n u.email_address,\n u.email_confirmed as `email_confirmed: bool`,\n u.is_without_password as `is_without_password: bool`,\n u.ip_address_creation,\n u.maybe_source as `maybe_source: enums::by_table::users::user_signup_source::UserSignupSource`,\n u.maybe_signup_method as `maybe_signup_method: enums::by_table::users::user_signup_method::UserSignupMethod`,\n u.created_at,\n u.maybe_referral_url,\n u.is_temporary as `is_temporary: bool`,\n us.subscription_namespace,\n us.subscription_product_slug,\n us.maybe_stripe_subscription_id,\n us.maybe_stripe_customer_id,\n us.maybe_stripe_product_id,\n us.maybe_stripe_price_id,\n us.maybe_stripe_subscription_status,\n us.maybe_stripe_recurring_interval,\n us.maybe_stripe_invoice_is_paid as `maybe_stripe_invoice_is_paid: bool`,\n us.maybe_cancel_at,\n us.maybe_canceled_at\nFROM users AS u\nINNER JOIN user_subscriptions AS us ON u.token = us.user_token\nWHERE\n u.id < ?\n AND u.user_deleted_at IS NULL\n AND u.mod_deleted_at IS NULL\nORDER BY u.id DESC\nLIMIT ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id: u64",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT",
|
||||
"char_set": 63,
|
||||
"max_size": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "username_is_not_customized: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "email_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email_confirmed: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "is_without_password: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "ip_address_creation",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "maybe_source: enums::by_table::users::user_signup_source::UserSignupSource",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_signup_method: enums::by_table::users::user_signup_method::UserSignupMethod",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "maybe_referral_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "is_temporary: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "subscription_namespace",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "subscription_product_slug",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "maybe_stripe_subscription_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "UNIQUE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "maybe_stripe_customer_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "maybe_stripe_product_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "maybe_stripe_price_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "maybe_stripe_subscription_status",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "maybe_stripe_recurring_interval",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "maybe_stripe_invoice_is_paid: bool",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "maybe_cancel_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "maybe_canceled_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "83840fa1a0712a326a26ae146a819f67a44fae927f294780d89892270075ebb7"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n UPDATE media_files\n SET maybe_thumbnail_version = ?\n WHERE token = ?\n LIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "87d7233bb9a4bcae7c9b7d55bb93fab182343847f0bcf8d8ce849f3a2dcfb704"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO prompts\nSET\n token = ?,\n prompt_type = ?,\n\n maybe_creator_user_token = ?,\n \n maybe_model_type = ?,\n maybe_generation_provider = ?,\n\n maybe_positive_prompt = ?,\n maybe_negative_prompt = ?,\n\n maybe_generation_mode = ?,\n maybe_aspect_ratio = ?,\n maybe_resolution = ?,\n maybe_batch_count = ?,\n maybe_generate_audio = ?,\n maybe_duration_seconds = ?,\n\n maybe_other_args = ?,\n\n creator_ip_address = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 15
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ccf92ebe0328d3019ac6b01be4b442df706a183362fa7e5c331f5a4bf1a74a00"
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n id,\n token as `token: MediaFileToken`,\n created_at as `created_at: DateTime<Utc>`,\n maybe_thumbnail_version as `maybe_thumbnail_version: u8`,\n public_bucket_directory_hash,\n maybe_public_bucket_prefix,\n maybe_public_bucket_extension\nFROM media_files\nWHERE\n id >= (SELECT COALESCE(MIN(id), 0) FROM media_files WHERE created_at >= NOW() - INTERVAL ? HOUR)\n AND id < ?\n AND media_class = ?\n AND maybe_thumbnail_version IS NULL\n AND user_deleted_at IS NULL\n AND mod_deleted_at IS NULL\nORDER BY id DESC\nLIMIT ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT",
|
||||
"char_set": 63,
|
||||
"max_size": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token: MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "created_at: DateTime<Utc>",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "maybe_thumbnail_version: u8",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "public_bucket_directory_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "daed2dcd03b3c9fbdb9057b743df078f43e2af87a2c31f418234f98da5ff979f"
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance for Claude Code when working with the Artcraft monorepo.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Artcraft is a web and desktop application for generating AI image and video. It is written in
|
||||
Rust and TypeScript and contains desktop, server, and frontend components.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
artcraft/
|
||||
├── _database/ # Schema definitions and migrations (MySQL, SQLite, Elasticsearch, etc.)
|
||||
│ ├── elasticsearch/ # Elasticsearch schema and queries
|
||||
│ └── sql/ # MySQL and SQLite schema definitions and migrations
|
||||
│ ├── artcraft_migrations/ # ArtCraft desktop app SQLite migrations
|
||||
│ ├── migrations/ # Server MySQL migrations
|
||||
│ └── migrations_squashed/ # Fully materialized MySQL schema definitions for most tables
|
||||
├── build/ # Dockerfile build instructions for server components
|
||||
├── crates/ # Rust workspace
|
||||
│ ├── api_clients/ # HTTP clients for calling internal and 3rd party services
|
||||
│ ├── cli/ # Command line tools
|
||||
│ ├── desktop/ # Desktop (Tauri) apps
|
||||
│ │ └── artcraft/ # (Important) ArtCraft, the desktop app. This is one of our main pieces of software
|
||||
│ ├── lib/ # Various utility libraries for servers, CLI tools, desktop, etc.
|
||||
│ ├── schema/ # Data definition layer: MySQL, SQlite, Redis, S3/R2 buckets, etc.
|
||||
│ │ ├── buckets/ # Declares R2 cloud bucket topology
|
||||
│ │ ├── database/ # MySQL, SQLite, Elasticsearch, Redis, etc.
|
||||
│ │ │ ├── elasticsearch_schema/ # Elasticsearch
|
||||
│ │ │ ├── migration/ # (deprecated) Online schema adapters for MySQL
|
||||
│ │ │ ├── mysql_queries/ # Sqlx MySQL queries for our backend monolith `storyteller-web`, jobs, etc.
|
||||
│ │ │ ├── redis_common/ # Redis support
|
||||
│ │ │ ├── redis_schema/ # Redis key and HKEY topology
|
||||
│ │ │ ├── sqlite_queries/ # (deprecated) Sqlite queries
|
||||
│ │ │ └── sqlite_tasks/ # Queries for the ArtCraft desktop app's "tasks" database.
|
||||
│ │ ├── public/ # Token identifier and enum variant definitions
|
||||
│ │ │ ├── composite_identifier/ # MySQL composite key system
|
||||
│ │ │ ├── enums/ # MySQL "enums" stored in VARCHAR fields.
|
||||
│ │ │ └── tokens/ # Primary database identifiers with Stripe-like ID prefixes, eg. "user_{entropy}"
|
||||
│ │ └── service/ # Backend HTTP services and jobs
|
||||
│ │ ├── job/ # Backend jobs.
|
||||
│ │ │ └── video_thumbnail_job/ # Render video thumbnails
|
||||
│ │ ├── plugins/ # Collections of reusable Actix-Web HTTP functions (user and billing systems)
|
||||
│ │ └── web/ # HTTP web servers
|
||||
│ │ └── storyteller_web/ # (Important) Our main HTTP API monolith and backend.
|
||||
│ └── frontend/ # Nx typescript monorepo for our websites and Tauri desktop apps
|
||||
│ ├── apps/ # Websites and Tauri desktop apps
|
||||
│ │ ├── artcraft/ # ArtCraft the Tauri app's frontend. Used in conjunction with `artcraft` the Rust crate.
|
||||
│ │ └── artcraft-website/ # The website for https://getartcraft.com
|
||||
│ └── libs/ # Support libraries, reusable React components, etc.
|
||||
└── Cargo.toml # Rust monorepo workspace
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
- Rust with no minimum supported version
|
||||
- Actix-web for HTTP services
|
||||
- SQLx for MySQL and SQLite
|
||||
- A mix of wreq and reqwest for Rust HTTP clients
|
||||
- TypeScript with Nx, React, Vite, Zustand, and Three.js
|
||||
- Use two spaces for indentation
|
||||
Generated
+529
-869
File diff suppressed because it is too large
Load Diff
+92
-67
@@ -6,27 +6,28 @@ resolver = "2"
|
||||
members = [
|
||||
# API clients for external services
|
||||
# These might be custom implementations or wrappers over other client libraries.
|
||||
"crates/api_clients/artcraft/artcraft_api_defs", # TODO: api_clients/{artcraft}/{api_defs,client}
|
||||
"crates/api_clients/artcraft/artcraft_api_defs",
|
||||
"crates/api_clients/artcraft/artcraft_client",
|
||||
"crates/api_clients/artcraft/artcraft_router",
|
||||
"crates/api_clients/cloud_storage",
|
||||
"crates/api_clients/fal_client",
|
||||
"crates/api_clients/google_drive_common",
|
||||
"crates/api_clients/google_drive_downloader",
|
||||
"crates/api_clients/google_sign_in",
|
||||
"crates/api_clients/grok_client",
|
||||
"crates/api_clients/midjourney_client",
|
||||
"crates/api_clients/muapi_client",
|
||||
"crates/api_clients/openai_sora_client",
|
||||
"crates/api_clients/openart_client",
|
||||
"crates/api_clients/muapi_client",
|
||||
"crates/api_clients/seedance2pro",
|
||||
"crates/api_clients/rootly_client",
|
||||
"crates/api_clients/runwayml_client",
|
||||
"crates/api_clients/seedance2pro_client",
|
||||
"crates/api_clients/thumbnail_generator",
|
||||
"crates/api_clients/world_labs_api",
|
||||
"crates/api_clients/world_labs_client",
|
||||
"crates/api_clients/worldlabs_api_client",
|
||||
"crates/api_clients/worldlabs_consumer_client",
|
||||
|
||||
# CLI tools for operations, etc.
|
||||
"crates/cli/devenv/dev-database-seed",
|
||||
"crates/cli/devenv/dev-upload-media-file",
|
||||
"crates/cli/devenv/scrape-test",
|
||||
"crates/cli/production/db-backfill",
|
||||
"crates/cli/production/db-backup",
|
||||
"crates/cli/production/db-cleanup",
|
||||
@@ -44,7 +45,6 @@ members = [
|
||||
"crates/lib/actix_cors_configs",
|
||||
"crates/lib/actix_helpers",
|
||||
"crates/lib/bootstrap",
|
||||
"crates/lib/bucket_paths",
|
||||
"crates/lib/build_metadata",
|
||||
"crates/lib/caching/memory_caching",
|
||||
"crates/lib/caching/memory_store",
|
||||
@@ -53,19 +53,14 @@ members = [
|
||||
"crates/lib/cloudflare_mitigation",
|
||||
"crates/lib/concurrency",
|
||||
"crates/lib/cookie_store",
|
||||
"crates/lib/cookies",
|
||||
"crates/lib/data/collections",
|
||||
"crates/lib/data/crockford",
|
||||
"crates/lib/data/datetimes",
|
||||
"crates/lib/data/primitives",
|
||||
"crates/lib/data/web_base64",
|
||||
"crates/lib/deprecated/config", # TODO(bt, 2023-02-13): Deprecate or repurpose
|
||||
"crates/lib/deprecated/http_server_common", # TODO(bt, 2023-03-20): Move useful pieces to actix_helpers
|
||||
"crates/lib/dimensions",
|
||||
"crates/lib/easyenv", # NB: Vendored version of https://github.com/echelon/easyenv.rs that we'll improve.
|
||||
"crates/lib/email_sender",
|
||||
"crates/lib/errors",
|
||||
"crates/lib/files/archives",
|
||||
"crates/lib/ffmpeg_utils",
|
||||
"crates/lib/files/file_to_base64_url",
|
||||
"crates/lib/files/filesys",
|
||||
"crates/lib/files/hashing",
|
||||
@@ -73,35 +68,41 @@ members = [
|
||||
"crates/lib/files/media",
|
||||
"crates/lib/files/mimetypes",
|
||||
"crates/lib/files/videos",
|
||||
"crates/lib/files/zip_archives",
|
||||
"crates/lib/http_headers",
|
||||
"crates/lib/idempotency",
|
||||
"crates/api_clients/artcraft/artcraft_router",
|
||||
"crates/lib/image_algorithms",
|
||||
"crates/lib/jobs_common",
|
||||
"crates/lib/jwt_light",
|
||||
"crates/lib/jwt_signer",
|
||||
"crates/lib/logging",
|
||||
"crates/lib/machine_learning/ml_weights_registry",
|
||||
"crates/lib/machine_learning/prompt_engineering",
|
||||
"crates/lib/markdown",
|
||||
"crates/lib/migration",
|
||||
"crates/lib/password",
|
||||
"crates/lib/server_environment",
|
||||
"crates/lib/sqlx_mysql_helpers",
|
||||
"crates/lib/storyteller_root",
|
||||
"crates/lib/subprocess_common",
|
||||
"crates/lib/test_data",
|
||||
"crates/lib/testing",
|
||||
"crates/lib/tts_common",
|
||||
"crates/lib/url_config",
|
||||
"crates/lib/url_utils",
|
||||
"crates/lib/user_input_common",
|
||||
"crates/lib/users",
|
||||
"crates/lib/web_scrapers",
|
||||
"crates/lib/uuid_utils",
|
||||
#"crates/lib/api_clients/fakeyou_client",
|
||||
#"crates/lib/machine_learning/ml_models",
|
||||
#"crates/lib/deprecated/machine_learning/ml_models",
|
||||
|
||||
# Shared libraries (Deprecated)
|
||||
"crates/lib/deprecated/config", # TODO(bt, 2023-02-13): Deprecate or repurpose
|
||||
"crates/lib/deprecated/email_sender",
|
||||
"crates/lib/deprecated/http_server_common", # TODO(bt, 2023-03-20): Move useful pieces to actix_helpers
|
||||
"crates/lib/deprecated/image_algorithms",
|
||||
"crates/lib/deprecated/machine_learning/ml_weights_registry",
|
||||
"crates/lib/deprecated/machine_learning/prompt_engineering",
|
||||
"crates/lib/deprecated/subprocess_common",
|
||||
"crates/lib/deprecated/tts_common",
|
||||
|
||||
# Schema (buckets): S3/R2 topology
|
||||
"crates/schema/buckets/bucket_paths",
|
||||
|
||||
# Schema (database): queries, database layouts, Redis keys, etc.
|
||||
"crates/schema/database/elasticsearch_schema",
|
||||
"crates/schema/database/migration",
|
||||
"crates/schema/database/mysql_queries",
|
||||
"crates/schema/database/redis_common",
|
||||
"crates/schema/database/redis_schema",
|
||||
@@ -116,31 +117,34 @@ members = [
|
||||
"crates/schema/public/tokens",
|
||||
|
||||
# Services: API servers, jobs, workers, etc.
|
||||
"crates/service/job/analytics_job",
|
||||
"crates/service/job/download_job",
|
||||
"crates/service/job/email_sender_job",
|
||||
"crates/service/job/es-update-job",
|
||||
"crates/service/job/inference_job",
|
||||
"crates/service/job/seedance2_pro_job",
|
||||
"crates/service/job/video_thumbnail_job",
|
||||
"crates/service/job/worldlabs_job",
|
||||
"crates/service/job/tts_download_job",
|
||||
"crates/service/job/tts_inference_job",
|
||||
"crates/service/job/w2l_download_job",
|
||||
"crates/service/job/w2l_inference_job",
|
||||
"crates/service/web/dummy_service",
|
||||
"crates/service/web/storyteller_web",
|
||||
|
||||
# Services (Deprecated) - may still have some use
|
||||
"crates/service/job/deprecated/analytics_job",
|
||||
"crates/service/job/deprecated/download_job",
|
||||
"crates/service/job/deprecated/email_sender_job",
|
||||
"crates/service/job/deprecated/es-update-job",
|
||||
"crates/service/job/deprecated/inference_job",
|
||||
"crates/service/job/deprecated/tts_download_job",
|
||||
"crates/service/job/deprecated/tts_inference_job",
|
||||
"crates/service/job/deprecated/w2l_download_job",
|
||||
"crates/service/job/deprecated/w2l_inference_job",
|
||||
|
||||
# Service Plugins: complete subsystems that can be plugged into services (users, billing, etc.)
|
||||
"crates/service/plugins/billing",
|
||||
"crates/service/plugins/billing_artcraft",
|
||||
"crates/service/plugins/component_traits",
|
||||
"crates/service/plugins/inference_workloads",
|
||||
"crates/service/plugins/user_traits_component",
|
||||
|
||||
# Testing code
|
||||
"crates/testing/test_data",
|
||||
"crates/testing/test_utils",
|
||||
|
||||
# Vendored code
|
||||
"crates/vendor/fal-rs",
|
||||
"crates/vendor/fal-rs/fal-derive",
|
||||
"crates/vendor/fal-rs/generate",
|
||||
"crates/vendor/limitation",
|
||||
"crates/vendor/tauri-plugin-http",
|
||||
"crates/vendor/Symphonia/symphonia",
|
||||
@@ -212,50 +216,57 @@ workspace-build-acceleration = { path = "crates/workspace-build-acceleration" }
|
||||
# Setting paths here ensures we don't need to do so in every crate's Cargo.toml
|
||||
# It makes refactoring much easier.
|
||||
actix_artcraft = { path = "crates/lib/actix_artcraft" }
|
||||
artcraft_router = { path = "crates/api_clients/artcraft/artcraft_router" }
|
||||
actix_helpers = { path = "crates/lib/actix_helpers" }
|
||||
artcraft_api_defs = { path = "crates/api_clients/artcraft/artcraft_api_defs" }
|
||||
artcraft_client = { path = "crates/api_clients/artcraft/artcraft_client" }
|
||||
artcraft_router = { path = "crates/api_clients/artcraft/artcraft_router" }
|
||||
bootstrap = { path = "crates/lib/bootstrap" }
|
||||
bucket_paths = { path = "crates/schema/buckets/bucket_paths" }
|
||||
build_metadata = { path = "crates/lib/build_metadata" }
|
||||
cloud_storage = { path = "crates/api_clients/cloud_storage" }
|
||||
cloudflare_errors = { path = "crates/lib/cloudflare_errors" }
|
||||
cloudflare_mitigation = { path = "crates/lib/cloudflare_mitigation" }
|
||||
collections = { path = "crates/lib/data/collections" }
|
||||
component_traits = { path = "crates/service/plugins/component_traits" }
|
||||
concurrency = { path = "crates/lib/concurrency" }
|
||||
cookie_store = { path = "crates/lib/cookie_store" }
|
||||
cookies = { path = "crates/lib/cookies" }
|
||||
crockford = { path = "crates/lib/data/crockford" }
|
||||
easyenv = { path = "crates/lib/easyenv" }
|
||||
enums = { path = "crates/schema/public/enums" }
|
||||
enums_public = { path = "crates/schema/public/enums_public" }
|
||||
errors = { path = "crates/lib/errors" }
|
||||
fal_client = { path = "crates/api_clients/fal_client" }
|
||||
ffmpeg_utils = { path = "crates/lib/ffmpeg_utils" }
|
||||
file_to_base64_url = { path = "crates/lib/files/file_to_base64_url" }
|
||||
filesys = { path = "crates/lib/files/filesys" }
|
||||
grok_client = { path = "crates/api_clients/grok_client" }
|
||||
rootly_client = { path = "crates/api_clients/rootly_client" }
|
||||
http_headers = { path = "crates/lib/http_headers" }
|
||||
idempotency = { path = "crates/lib/idempotency" }
|
||||
images = { path = "crates/lib/files/images" }
|
||||
jobs_common = { path = "crates/lib/jobs_common" }
|
||||
jwt_light = { path = "crates/lib/jwt_light" }
|
||||
jwt_signer = { path = "crates/lib/jwt_signer" }
|
||||
memory_caching = { path = "crates/lib/caching/memory_caching" }
|
||||
memory_store = { path = "crates/lib/caching/memory_store" }
|
||||
midjourney_client = { path = "crates/api_clients/midjourney_client" }
|
||||
mimetypes = { path = "crates/lib/files/mimetypes" }
|
||||
openai_sora_client = { path = "crates/api_clients/openai_sora_client" }
|
||||
muapi_client = { path = "crates/api_clients/muapi_client" }
|
||||
seedance2pro = { path = "crates/api_clients/seedance2pro" }
|
||||
mysql_queries = { path = "crates/schema/database/mysql_queries" }
|
||||
openai_sora_client = { path = "crates/api_clients/openai_sora_client" }
|
||||
primitives = { path = "crates/lib/data/primitives" }
|
||||
seedance2pro_client = { path = "crates/api_clients/seedance2pro_client" }
|
||||
shared_service_components = { path = "crates/lib/shared_service_components" }
|
||||
sqlite_tasks = { path = "crates/schema/database/sqlite_tasks" }
|
||||
artcraft_client = { path = "crates/api_clients/artcraft/artcraft_client" }
|
||||
subprocess_common = { path = "crates/lib/subprocess_common" }
|
||||
test_data = { path = "crates/lib/test_data" }
|
||||
testing = { path = "crates/lib/testing" }
|
||||
subprocess_common = { path = "crates/lib/deprecated/subprocess_common" }
|
||||
test_data = { path = "crates/testing/test_data" }
|
||||
test_utils = { path = "crates/testing/test_utils" }
|
||||
tokens = { path = "crates/schema/public/tokens" }
|
||||
url_utils = { path = "crates/lib/url_utils" }
|
||||
users = { path = "crates/lib/users" }
|
||||
uuid_utils = { path = "crates/lib/uuid_utils" }
|
||||
web_base64 = { path = "crates/lib/data/web_base64" }
|
||||
world_labs_api = { path = "crates/api_clients/world_labs_api" }
|
||||
world_labs_client = { path = "crates/api_clients/world_labs_client" }
|
||||
worldlabs_api_client = { path = "crates/api_clients/worldlabs_api_client" }
|
||||
worldlabs_consumer_client = { path = "crates/api_clients/worldlabs_consumer_client" }
|
||||
|
||||
# External libs
|
||||
# Centrally pinned versions so that we can uniformly upgrade/downgrade versions across the workspace
|
||||
@@ -271,32 +282,42 @@ actix-web = "4.7.0" # TODO(bt): We're behind and need to bump versions.
|
||||
actix-web-actors = "4.3.1+deprecated"
|
||||
actix-web-lab = "0.20.2"
|
||||
anyhow = "1.0.102"
|
||||
assertor = "0.0.3"
|
||||
base64 = "0.22.1"
|
||||
bcrypt = "0.15"
|
||||
bstr = "1.12.1"
|
||||
bytes = "1.10.1"
|
||||
chrono = { version = "0.4.41", features = ["serde"] }
|
||||
clap = { version = "4.5.60", features = ["derive"] }
|
||||
byteorder = "1.5.0"
|
||||
bytes = "1.11.1"
|
||||
chrono = { version = "0.4.44", features = ["serde"] }
|
||||
clap = { version = "=4.5.60", features = ["derive"] }
|
||||
cookie = "0.18.1"
|
||||
dotenv = "0.15.0"
|
||||
elasticsearch = { version = "8.5.0-alpha.1", default-features = false, features = ["rustls-tls"] }
|
||||
env = "1.0.1"
|
||||
env_logger = "0.11.9"
|
||||
futures = { version = "0.3.31" }
|
||||
hex-literal = "1.0.0"
|
||||
indexmap = "2.9.0"
|
||||
futures = { version = "0.3.32" }
|
||||
hex-literal = "1.1.0"
|
||||
hostname = "0.4.0"
|
||||
indexmap = "2.13.0"
|
||||
log = "0.4.29"
|
||||
md-5 = "0.10.6" # insecure but used for gravatar
|
||||
once_cell = "1.21.3"
|
||||
mockall = "0.12.1"
|
||||
once_cell = "1.21.4"
|
||||
r2d2 = "0.8.10"
|
||||
r2d2_redis = "0.14.0"
|
||||
rand = "0.9.1"
|
||||
redis = { version = "1.0.2", features = ["r2d2", "tokio-rustls-comp", "tokio-comp", "cluster-async", "aio"] }
|
||||
regex = "1.12.3"
|
||||
reqwest = { version = "0.12.23", default-features = false, features = [ "charset", "http2", "system-proxy", "json", "cookies", "rustls-tls", "gzip" ] }
|
||||
reqwest-websocket = { version = "0.5.0" }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_derive = "1.0.219"
|
||||
serde_json = "1.0.140"
|
||||
rust-s3 = { version = "0.36.0-beta.2", default-features = false, features = ["fail-on-err", "tags", "tokio-rustls-tls"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_derive = "1.0.228"
|
||||
serde_json = "1.0.149"
|
||||
serde_yaml = "0.9.34+deprecated"
|
||||
sha2 = "0.11.0-rc.2"
|
||||
sha2 = "0.11.0-rc.5"
|
||||
sha3 = "0.10.8"
|
||||
speculoos = "0.11.0"
|
||||
strum = { version = "0.28.0", features = ["derive"] }
|
||||
tauri = { version = "2.8.3", features = ["unstable", "devtools"] } # NB: "devtools" prevents App Store distribution; "ubstable" is needed for window access
|
||||
tauri-plugin-dialog = "2.3.3"
|
||||
@@ -304,12 +325,16 @@ tauri-plugin-fs = "2.4.2"
|
||||
tauri-plugin-log = "2.6.0"
|
||||
tauri-plugin-upload = "2.3.1"
|
||||
tempdir = "0.3.7"
|
||||
tempfile = "3.20.0"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.1", features = ["macros"] }
|
||||
toml = "0.8.23"
|
||||
url = { version = "2.5.4", features = ["serde"] }
|
||||
uuid = "1.18.1"
|
||||
tempfile = "3.27.0"
|
||||
thiserror = "2.0.18"
|
||||
time = "0.3.36"
|
||||
tokio = { version = "1.50.0", features = ["macros"] }
|
||||
tokio-util = "0.7.12"
|
||||
toml = "1.0.7+spec-1.1.0"
|
||||
url = { version = "2.5.8", features = ["serde"] }
|
||||
utoipa = { version = "5.4.0", features = ["chrono", "actix_extras", "url"] }
|
||||
uuid = "1.22.0"
|
||||
walkdir = "2.4.0"
|
||||
|
||||
# NB: wreq gets past fingerprinting, but we have to deal with platform-specific build issues.
|
||||
#
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE prompts
|
||||
DROP COLUMN maybe_generation_mode,
|
||||
DROP COLUMN maybe_aspect_ratio,
|
||||
DROP COLUMN maybe_resolution,
|
||||
DROP COLUMN maybe_duration,
|
||||
DROP COLUMN maybe_batch_count,
|
||||
DROP COLUMN maybe_generate_audio;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE prompts
|
||||
ADD COLUMN maybe_generation_mode VARCHAR(24) DEFAULT NULL,
|
||||
ADD COLUMN maybe_aspect_ratio VARCHAR(24) DEFAULT NULL,
|
||||
ADD COLUMN maybe_resolution VARCHAR(16) DEFAULT NULL,
|
||||
ADD COLUMN maybe_duration VARCHAR(8) DEFAULT NULL,
|
||||
ADD COLUMN maybe_batch_count TINYINT UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN maybe_generate_audio BOOLEAN DEFAULT NULL;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE prompts
|
||||
DROP COLUMN maybe_duration_seconds,
|
||||
ADD COLUMN maybe_duration VARCHAR(8) DEFAULT NULL;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE prompts
|
||||
DROP COLUMN maybe_duration,
|
||||
ADD COLUMN maybe_duration_seconds INT UNSIGNED DEFAULT NULL;
|
||||
@@ -27,6 +27,8 @@ CREATE TABLE prompts (
|
||||
-- What type of model was used to generate the result.
|
||||
-- NB: We're conflating prompts with outputs, but in a
|
||||
-- sense the model is inextricably part of the prompt.
|
||||
--
|
||||
-- Represented by the `CommonModelType` enum.
|
||||
maybe_model_type VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- What service provided the generation.
|
||||
@@ -52,6 +54,29 @@ CREATE TABLE prompts (
|
||||
-- TEXT = 65,535 bytes (64 KiB), ~= 4 bytes per UTF-8 character, ~ 16383 characters.
|
||||
maybe_other_args TEXT DEFAULT NULL,
|
||||
|
||||
-- ========== GENERATION PARAMETERS ==========
|
||||
|
||||
-- Represented by the enum `CommonGenerationMode`.
|
||||
-- The generation mode (eg. keyframe, reference, inpaint, etc.)
|
||||
maybe_generation_mode VARCHAR(24) DEFAULT NULL,
|
||||
|
||||
-- Represented by the enum `CommonAspectRatio`.
|
||||
-- The aspect ratio for the prompt (eg. square, auto, wide_three_by_two, etc.)
|
||||
maybe_aspect_ratio VARCHAR(24) DEFAULT NULL,
|
||||
|
||||
-- Represented by the enum `CommonResolution`.
|
||||
-- The resolution for the prompt (eg. four_k, 720p, etc.)
|
||||
maybe_resolution VARCHAR(16) DEFAULT NULL,
|
||||
|
||||
-- The duration in seconds
|
||||
maybe_duration_seconds INT UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- The number of outputs to generate (0-255)
|
||||
maybe_batch_count TINYINT UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- Whether to generate audio
|
||||
maybe_generate_audio BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- ========== ABUSE TRACKING ==========
|
||||
|
||||
-- For abuse tracking.
|
||||
|
||||
@@ -66,6 +66,7 @@ CREATE TABLE users (
|
||||
-- - "explore_media"
|
||||
-- - "studio"
|
||||
-- - "video_style_transfer"
|
||||
-- - "sd_wl" (seedance whitelist)
|
||||
maybe_feature_flags VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- DEPRECATED
|
||||
|
||||
@@ -130,47 +130,20 @@ RUN echo "Disk usage at current directory (after tests):"
|
||||
RUN pwd
|
||||
RUN du -hsc * | sort -hr
|
||||
|
||||
# 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 seedance2-pro-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin worldlabs-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin dummy-service
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin analytics-job
|
||||
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin email-sender-job
|
||||
|
||||
# Build all the binaries in a single cargo invocation.
|
||||
# This lets cargo parallelize shared dependency compilation across all targets,
|
||||
# which is significantly faster than building each binary sequentially.
|
||||
RUN SQLX_OFFLINE=true \
|
||||
LD_LIBRARY_PATH=/usr/lib:${LD_LIBRARY_PATH} \
|
||||
$HOME/.cargo/bin/cargo build \
|
||||
--release \
|
||||
--bin storyteller-web \
|
||||
--bin seedance2-pro-job \
|
||||
--bin worldlabs-job \
|
||||
--bin video-thumbnail-job \
|
||||
--bin dummy-service \
|
||||
--bin analytics-job \
|
||||
--bin email-sender-job \
|
||||
--bin es-update-job
|
||||
|
||||
# Print a report on disk space
|
||||
@@ -210,6 +183,7 @@ RUN echo -n ${GIT_SHA} > GIT_SHA
|
||||
COPY --from=builder /tmp/target/release/storyteller-web /
|
||||
COPY --from=builder /tmp/target/release/seedance2-pro-job /
|
||||
COPY --from=builder /tmp/target/release/worldlabs-job /
|
||||
COPY --from=builder /tmp/target/release/video-thumbnail-job /
|
||||
COPY --from=builder /tmp/target/release/dummy-service /
|
||||
COPY --from=builder /tmp/target/release/analytics-job /
|
||||
COPY --from=builder /tmp/target/release/email-sender-job /
|
||||
|
||||
@@ -178,11 +178,11 @@ RUN touch .env-secrets
|
||||
|
||||
# Some services have default env files that live under their code directories
|
||||
# These should also be readable from the relative current path
|
||||
COPY crates/service/job/download_job/config/download-job.common.env .
|
||||
COPY crates/service/job/download_job/config/download-job.production.env .
|
||||
COPY crates/service/job/deprecated/download_job/config/download-job.common.env .
|
||||
COPY crates/service/job/deprecated/download_job/config/download-job.production.env .
|
||||
|
||||
COPY crates/service/job/inference_job/config/inference-job.common.env .
|
||||
COPY crates/service/job/inference_job/config/inference-job.production.env .
|
||||
COPY crates/service/job/deprecated/inference_job/config/inference-job.common.env .
|
||||
COPY crates/service/job/deprecated/inference_job/config/inference-job.production.env .
|
||||
|
||||
# # Need python to make use of other containers' venv
|
||||
# # TODO(bt,2023-04-26): This is only necessary for download-job and inference-job
|
||||
|
||||
@@ -33,7 +33,7 @@ serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
utoipa = { version = "4", features = ["chrono", "actix_extras"] }
|
||||
utoipa.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow.workspace = true
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
// TODO(bt,2025-08-20): Replace the storyteller-web version of this.
|
||||
// All it needs is the impl ported into a builder.
|
||||
|
||||
/// Cover image links can only be jpg, png, etc. No videos.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct CoverImageLinks {
|
||||
/// Primary link to the cover image via the CDN.
|
||||
pub cdn_url: Url,
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
use crate::common::responses::cover_image_links::CoverImageLinks;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
// TODO(bt,2025-08-20): Replace the storyteller-web version of this.
|
||||
// We can't drop the old version just yet due to the `impl` (easy)
|
||||
@@ -8,7 +9,7 @@ use serde_derive::{Deserialize, Serialize};
|
||||
/// Everything we need to create a cover image.
|
||||
/// Cover images are small descriptive images that can be set for any media file.
|
||||
/// If a cover image is set, this is the path to the asset.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct MediaFileCoverImageDetails {
|
||||
// /// (DEPRECATED) URL path to the media file
|
||||
// #[deprecated(note="This field doesn't point to the full URL. Use media_links instead to leverage the CDN.")]
|
||||
@@ -36,7 +37,7 @@ pub struct MediaFileCoverImageDetails {
|
||||
|
||||
/// The default cover is composed of an image and color pair that are
|
||||
/// predefined by the frontend.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct MediaFileDefaultCover {
|
||||
pub image_index: u8,
|
||||
pub color_index: u8,
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Everything we need to refer to a user on the public web interface.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct UserDetailsLight {
|
||||
/// The token for the user
|
||||
pub user_token: UserToken,
|
||||
@@ -26,7 +27,7 @@ pub struct UserDetailsLight {
|
||||
// In the future, we'll also support user-uploaded avatars that we store on our servers.
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct UserDefaultAvatarInfo {
|
||||
pub image_index: u8,
|
||||
pub color_index: u8,
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_image_model::CommonImageModel;
|
||||
use enums::common::generation::common_video_resolution::CommonVideoResolution;
|
||||
use enums::common::generation::common_resolution::CommonResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
|
||||
pub const ESTIMATE_IMAGE_COST_PATH: &str = "/v1/generate/cost_estimate/image";
|
||||
@@ -27,7 +27,7 @@ pub struct EstimateImageCostRequest {
|
||||
pub aspect_ratio: Option<CommonAspectRatio>,
|
||||
|
||||
/// Optional resolution.
|
||||
pub resolution: Option<CommonVideoResolution>,
|
||||
pub resolution: Option<CommonResolution>,
|
||||
|
||||
/// Number of images to generate in parallel.
|
||||
pub image_batch_count: Option<u16>,
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_video_model::CommonVideoModel;
|
||||
use enums::common::generation::common_video_resolution::CommonVideoResolution;
|
||||
use enums::common::generation::common_resolution::CommonResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
|
||||
pub const ESTIMATE_VIDEO_COST_PATH: &str = "/v1/generate/cost_estimate/video";
|
||||
@@ -30,7 +30,7 @@ pub struct EstimateVideoCostRequest {
|
||||
pub aspect_ratio: Option<CommonAspectRatio>,
|
||||
|
||||
/// Optional resolution.
|
||||
pub resolution: Option<CommonVideoResolution>,
|
||||
pub resolution: Option<CommonResolution>,
|
||||
|
||||
/// Duration in seconds.
|
||||
pub duration_seconds: Option<u16>,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::common::responses::job_details::{JobDetailsLipsyncRequest, JobDetailsLivePortraitRequest};
|
||||
use crate::common::responses::media_links::MediaLinks;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums::common::job_status_plus::JobStatusPlus;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::users::user_signup_method::UserSignupMethod;
|
||||
use enums::by_table::users::user_signup_source::UserSignupSource;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const MODERATOR_LIST_SUBSCRIBING_USERS_BY_SIGNUP_DATE_PATH: &str = "/v1/moderation/users/list_subscribers_by_signup_date";
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ModeratorListSubscribingUsersBySignupDateRequest {
|
||||
/// Optional cursor for pagination. Pass the `next_cursor` from a previous response.
|
||||
pub id_cursor: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListSubscribingUsersBySignupDateResponse {
|
||||
pub success: bool,
|
||||
pub users: Vec<ModeratorListSubscribingUsersBySignupDateEntry>,
|
||||
/// The cursor for the next page. `None` if there are no more results.
|
||||
pub next_cursor: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListSubscribingUsersBySignupDateEntry {
|
||||
// -- User fields --
|
||||
pub id: u64,
|
||||
pub token: UserToken,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub username_is_not_customized: bool,
|
||||
pub email_address: String,
|
||||
pub email_confirmed: bool,
|
||||
pub is_without_password: bool,
|
||||
pub ip_address_creation: String,
|
||||
pub maybe_source: Option<UserSignupSource>,
|
||||
pub maybe_signup_method: Option<UserSignupMethod>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub maybe_referral_url: Option<String>,
|
||||
pub is_temporary: bool,
|
||||
|
||||
// TODO: Use enum types/strong types -
|
||||
// -- Subscription fields --
|
||||
pub subscription_namespace: String,
|
||||
pub subscription_product_slug: String,
|
||||
pub maybe_stripe_subscription_id: Option<String>,
|
||||
pub maybe_stripe_customer_id: Option<String>,
|
||||
pub maybe_stripe_product_id: Option<String>,
|
||||
pub maybe_stripe_price_id: Option<String>,
|
||||
pub maybe_stripe_subscription_status: Option<String>,
|
||||
pub maybe_stripe_recurring_interval: Option<String>,
|
||||
pub maybe_stripe_invoice_is_paid: Option<bool>,
|
||||
pub maybe_cancel_at: Option<DateTime<Utc>>,
|
||||
pub maybe_canceled_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::users::user_signup_method::UserSignupMethod;
|
||||
use enums::by_table::users::user_signup_source::UserSignupSource;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const MODERATOR_LIST_USERS_BY_SIGNUP_DATE_PATH: &str = "/v1/moderation/users/list_all_by_signup_date";
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ModeratorListUsersBySignupDateRequest {
|
||||
/// Optional cursor for pagination. Pass the `next_cursor` from a previous response.
|
||||
pub id_cursor: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListUsersBySignupDateResponse {
|
||||
pub success: bool,
|
||||
pub users: Vec<ModeratorListUsersBySignupDateEntry>,
|
||||
/// The cursor for the next page. `None` if there are no more results.
|
||||
pub next_cursor: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListUsersBySignupDateEntry {
|
||||
pub id: u64,
|
||||
pub token: UserToken,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub username_is_not_customized: bool,
|
||||
pub email_address: String,
|
||||
pub email_confirmed: bool,
|
||||
pub is_without_password: bool,
|
||||
pub ip_address_creation: String,
|
||||
pub maybe_source: Option<UserSignupSource>,
|
||||
pub maybe_signup_method: Option<UserSignupMethod>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub maybe_referral_url: Option<String>,
|
||||
pub is_temporary: bool,
|
||||
}
|
||||
@@ -1,2 +1,4 @@
|
||||
pub mod list_subscribing_users_by_signup_date;
|
||||
pub mod list_users_by_signup_date;
|
||||
pub mod user_lookup;
|
||||
pub mod user_lookup_by_stripe_customer_id;
|
||||
pub mod user_lookup_by_stripe_customer_id;
|
||||
@@ -1,8 +1,11 @@
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_generation_mode::CommonGenerationMode;
|
||||
use enums::common::generation::common_model_type::CommonModelType;
|
||||
use enums::common::generation::common_resolution::CommonResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
use utoipa::ToSchema;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::common::model_type::ModelType;
|
||||
|
||||
pub const CREATE_PROMPT_PATH: &str = "/v1/prompts/create";
|
||||
|
||||
@@ -14,14 +17,32 @@ pub struct CreatePromptRequest {
|
||||
/// OPTIONAL. The positive prompt.
|
||||
pub positive_prompt: Option<String>,
|
||||
|
||||
/// OPTIONAL. The positive prompt.
|
||||
/// OPTIONAL. The negative prompt.
|
||||
pub negative_prompt: Option<String>,
|
||||
|
||||
|
||||
/// OPTIONAL. The model type.
|
||||
pub model_type: Option<ModelType>,
|
||||
pub model_type: Option<CommonModelType>,
|
||||
|
||||
/// OPTIONAL. The service used.
|
||||
pub generation_provider: Option<GenerationProvider>,
|
||||
|
||||
/// OPTIONAL. The generation mode (eg. keyframe, reference, inpaint, etc.)
|
||||
pub maybe_generation_mode: Option<CommonGenerationMode>,
|
||||
|
||||
/// OPTIONAL. The aspect ratio (eg. square, auto, wide_three_by_two, etc.)
|
||||
pub maybe_aspect_ratio: Option<CommonAspectRatio>,
|
||||
|
||||
/// OPTIONAL. The resolution (eg. one_k, two_k, four_k, etc.)
|
||||
pub maybe_resolution: Option<CommonResolution>,
|
||||
|
||||
/// OPTIONAL. The number of outputs to generate (0-255).
|
||||
pub maybe_batch_count: Option<u8>,
|
||||
|
||||
/// OPTIONAL. Whether to generate audio.
|
||||
pub maybe_generate_audio: Option<bool>,
|
||||
|
||||
/// OPTIONAL. The duration in seconds.
|
||||
pub maybe_duration_seconds: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
use crate::common::responses::media_links::MediaLinks;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::prompt_context_items::prompt_context_semantic_type::PromptContextSemanticType;
|
||||
use enums::by_table::prompts::prompt_type::PromptType;
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_generation_mode::CommonGenerationMode;
|
||||
use enums::common::generation::common_model_type::CommonModelType;
|
||||
use enums::common::generation::common_resolution::CommonResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
use utoipa::ToSchema;
|
||||
use enums::common::generation::common_model_class::CommonModelClass;
|
||||
|
||||
pub const GET_PROMPT_PATH: &str = "/v1/prompts/{token}";
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct GetPromptPathInfo {
|
||||
pub token: PromptToken,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct GetPromptSuccessResponse {
|
||||
pub success: bool,
|
||||
pub prompt: PromptInfo,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct GetPromptImageContextItem {
|
||||
pub media_token: MediaFileToken,
|
||||
pub semantic: PromptContextSemanticType,
|
||||
pub media_links: MediaLinks,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct PromptInfo {
|
||||
pub token: PromptToken,
|
||||
|
||||
/// The type of prompt.
|
||||
/// Note: Prompts may or may not be compatible across systems.
|
||||
pub prompt_type: PromptType,
|
||||
|
||||
/// The type of model used
|
||||
pub maybe_model_type: Option<CommonModelType>,
|
||||
|
||||
/// The class of model used
|
||||
pub maybe_model_class: Option<CommonModelClass>,
|
||||
|
||||
/// The service provider used
|
||||
pub maybe_generation_provider: Option<GenerationProvider>,
|
||||
|
||||
/// Positive prompt (technically optional, but usually present)
|
||||
pub maybe_positive_prompt: Option<String>,
|
||||
|
||||
/// Negative prompt (optional)
|
||||
pub maybe_negative_prompt: Option<String>,
|
||||
|
||||
/// OPTIONAL. The generation mode (eg. keyframe, reference, inpaint, etc.)
|
||||
pub maybe_generation_mode: Option<CommonGenerationMode>,
|
||||
|
||||
/// OPTIONAL. The aspect ratio (eg. square, auto, wide_three_by_two, etc.)
|
||||
pub maybe_aspect_ratio: Option<CommonAspectRatio>,
|
||||
|
||||
/// OPTIONAL. The resolution (eg. one_k, two_k, four_k, etc.)
|
||||
pub maybe_resolution: Option<CommonResolution>,
|
||||
|
||||
/// OPTIONAL. The number of outputs to generate (0-255).
|
||||
pub maybe_batch_count: Option<u8>,
|
||||
|
||||
/// OPTIONAL. Whether to generate audio.
|
||||
pub maybe_generate_audio: Option<bool>,
|
||||
|
||||
/// OPTIONAL. The duration in seconds.
|
||||
pub maybe_duration_seconds: Option<u32>,
|
||||
|
||||
/// Context images (optional)
|
||||
pub maybe_context_images: Option<Vec<GetPromptImageContextItem>>,
|
||||
|
||||
/// Scheduled / travel prompt (optional)
|
||||
pub maybe_travel_prompt: Option<String>,
|
||||
|
||||
/// If a "style" was used, this is the name of it.
|
||||
/// This might not be present for all types of inference
|
||||
/// and typically only applies to video style transfer.
|
||||
pub maybe_style_name: Option<StyleTransferName>,
|
||||
|
||||
/// How many milliseconds it took to run generation.
|
||||
pub maybe_inference_duration_millis: Option<u64>,
|
||||
|
||||
/// If a "strength" was used.
|
||||
/// Typically only for video style transfer.
|
||||
pub maybe_strength: Option<f32>,
|
||||
|
||||
/// If a frame skip setting was used.
|
||||
pub maybe_frame_skip: Option<u8>,
|
||||
|
||||
/// If a face detailer was used.
|
||||
/// This might not be present for all types of inference
|
||||
/// and typically only applies to video style transfer.
|
||||
pub used_face_detailer: bool,
|
||||
|
||||
/// If an upscaling pass was used.
|
||||
/// This might not be present for all types of inference
|
||||
/// and typically only applies to video style transfer.
|
||||
pub used_upscaler: bool,
|
||||
|
||||
/// If lipsync was enabled.
|
||||
/// This might not be present for all types of inference
|
||||
/// and typically only applies to video style transfer.
|
||||
pub lipsync_enabled: bool,
|
||||
|
||||
/// If LCM was disabled.
|
||||
/// Only staff can do this for now.
|
||||
pub lcm_disabled: bool,
|
||||
|
||||
/// If the cinematic workflow was used.
|
||||
/// Only staff can do this for now.
|
||||
pub use_cinematic: bool,
|
||||
|
||||
/// If a global IP Adapter Image was used, this is the details.
|
||||
/// NB: We can't easily query for this without another DB round trip,
|
||||
/// so the frontend should query for it instead.
|
||||
pub maybe_global_ipa_image_token: Option<MediaFileToken>,
|
||||
|
||||
/// Fields that only moderators should see.
|
||||
pub maybe_moderator_fields: Option<PromptInfoModeratorFields>,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct PromptInfoModeratorFields {
|
||||
/// How many milliseconds it took to run generation.
|
||||
pub maybe_inference_duration_millis: Option<u64>,
|
||||
|
||||
/// Version of Yae's workflow
|
||||
/// Used for logging and debugging by the art team.
|
||||
pub main_ipa_workflow: Option<String>,
|
||||
|
||||
/// Version of Yae's face detailer workflow
|
||||
/// Used for logging and debugging by the art team.
|
||||
pub face_detailer_workflow: Option<String>,
|
||||
|
||||
/// Version of Yae's upscaler workflow
|
||||
/// Used for logging and debugging by the art team.
|
||||
pub upscaler_workflow: Option<String>,
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod create_prompt;
|
||||
pub mod create_prompt;
|
||||
pub mod get_prompt;
|
||||
@@ -28,7 +28,7 @@ cloudflare_errors.workspace = true
|
||||
enums.workspace = true
|
||||
enums_public.workspace = true
|
||||
errors.workspace = true
|
||||
idempotency.workspace = true
|
||||
uuid_utils.workspace = true
|
||||
mimetypes.workspace = true
|
||||
tokens.workspace = true
|
||||
|
||||
|
||||
-1
@@ -5,7 +5,6 @@ use crate::utils::basic_json_delete_request::basic_json_delete_request;
|
||||
use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess;
|
||||
use artcraft_api_defs::media_file::delete_media_file::DeleteMediaFileRequest;
|
||||
use artcraft_api_defs::subscriptions::get_session_subscription::GetSessionSubscriptionResponse;
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use log::debug;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
|
||||
+1
-9
@@ -7,16 +7,9 @@ use crate::utils::constants::{APPLICATION_JSON, USER_AGENT};
|
||||
use crate::utils::filter_bad_response::filter_bad_response;
|
||||
use crate::utils::http_get_anonymous::http_get_anonymous;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::common::visibility::Visibility;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::debug;
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::Client;
|
||||
@@ -52,7 +45,6 @@ pub struct LegacyUploadMediaFileFromFileArgs<'a, P: AsRef<Path>> {
|
||||
// pub maybe_batch_token: Option<&'a BatchGenerationToken>,
|
||||
}
|
||||
|
||||
|
||||
/// Upload using the legacy endpoint (spz, etc.)
|
||||
pub async fn legacy_upload_media_file_from_file<P: AsRef<Path>>(
|
||||
args: LegacyUploadMediaFileFromFileArgs<'_, P>,
|
||||
|
||||
+1
-8
@@ -7,15 +7,8 @@ use crate::utils::constants::{APPLICATION_JSON, USER_AGENT};
|
||||
use crate::utils::filter_bad_response::filter_bad_response;
|
||||
use crate::utils::http_get_anonymous::http_get_anonymous;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::common::visibility::Visibility;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::debug;
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::Client;
|
||||
|
||||
+1
-9
@@ -7,16 +7,9 @@ use crate::utils::constants::{APPLICATION_JSON, USER_AGENT};
|
||||
use crate::utils::filter_bad_response::filter_bad_response;
|
||||
use crate::utils::http_get_anonymous::http_get_anonymous;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::common::visibility::Visibility;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::debug;
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::Client;
|
||||
@@ -52,7 +45,6 @@ pub struct UploadImageFromFileArgs<'a, P: AsRef<Path>> {
|
||||
pub maybe_batch_token: Option<&'a BatchGenerationToken>,
|
||||
}
|
||||
|
||||
|
||||
/// Upload an image media file from a file.
|
||||
pub async fn upload_image_media_file_from_file<P: AsRef<Path>>(
|
||||
args: UploadImageFromFileArgs<'_, P>,
|
||||
|
||||
+1
-8
@@ -5,15 +5,8 @@ use crate::utils::constants::{APPLICATION_JSON, USER_AGENT};
|
||||
use crate::utils::filter_bad_response::filter_bad_response;
|
||||
use crate::utils::http_get_anonymous::http_get_anonymous;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::common::visibility::Visibility;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::debug;
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::Client;
|
||||
|
||||
+1
-10
@@ -5,15 +5,8 @@ use crate::utils::constants::{APPLICATION_JSON, USER_AGENT};
|
||||
use crate::utils::filter_bad_response::filter_bad_response;
|
||||
use crate::utils::http_get_anonymous::http_get_anonymous;
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::common::visibility::Visibility;
|
||||
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
|
||||
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::debug;
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::Client;
|
||||
@@ -49,8 +42,6 @@ pub struct UploadVideoFromFileArgs<'a, P: AsRef<Path>> {
|
||||
// pub maybe_batch_token: Option<&'a BatchGenerationToken>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO(bt,2025-04-22): Share API definitions between client and server in common crate.
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
||||
@@ -20,10 +20,10 @@ artcraft_api_defs.workspace = true
|
||||
artcraft_client.workspace = true
|
||||
fal_client.workspace = true
|
||||
muapi_client.workspace = true
|
||||
seedance2pro.workspace = true
|
||||
seedance2pro_client.workspace = true
|
||||
tokens.workspace = true
|
||||
url_utils.workspace = true
|
||||
world_labs_api.workspace = true
|
||||
worldlabs_api_client.workspace = true
|
||||
|
||||
# External
|
||||
anyhow.workspace = true
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use seedance2pro::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession;
|
||||
|
||||
pub struct RouterSeedance2ProClient {
|
||||
pub(crate) session: Seedance2ProSession,
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
||||
use artcraft_client::error::storyteller_error::StorytellerError;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use muapi_client::error::muapi_error::MuapiError;
|
||||
use seedance2pro::error::seedance2pro_error::Seedance2ProError;
|
||||
use seedance2pro_client::error::seedance2pro_error::Seedance2ProError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProviderError {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
use crate::generate::generate_splat::plan::artcraft::plan_generate_splat_artcraft_marble_0p1_mini::PlanArtcraftMarble0p1Mini;
|
||||
use crate::generate::generate_splat::splat_generation_cost_estimate::SplatGenerationCostEstimate;
|
||||
use world_labs_api::api::api_types::world_labs_model::WorldLabsModel;
|
||||
use world_labs_api::pricing::check_pricing::{calculate_cost, InputType};
|
||||
use worldlabs_api_client::api::api_types::world_labs_model::WorldLabsModel;
|
||||
use worldlabs_api_client::pricing::check_pricing::{calculate_cost, InputType};
|
||||
|
||||
pub(crate) fn estimate_splat_cost_artcraft_marble_0p1_mini(
|
||||
plan: &PlanArtcraftMarble0p1Mini<'_>,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
use crate::generate::generate_splat::plan::artcraft::plan_generate_splat_artcraft_marble_0p1_plus::PlanArtcraftMarble0p1Plus;
|
||||
use crate::generate::generate_splat::splat_generation_cost_estimate::SplatGenerationCostEstimate;
|
||||
use world_labs_api::api::api_types::world_labs_model::WorldLabsModel;
|
||||
use world_labs_api::pricing::check_pricing::{calculate_cost, InputType};
|
||||
use worldlabs_api_client::api::api_types::world_labs_model::WorldLabsModel;
|
||||
use worldlabs_api_client::pricing::check_pricing::{calculate_cost, InputType};
|
||||
|
||||
pub(crate) fn estimate_splat_cost_artcraft_marble_0p1_plus(
|
||||
plan: &PlanArtcraftMarble0p1Plus<'_>,
|
||||
|
||||
+8
-6
@@ -1,6 +1,6 @@
|
||||
use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::Seedance2p0BatchCount;
|
||||
use seedance2pro::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro::requests::generate_video::generate_video::{BatchCount, GenerateVideoArgs, Resolution};
|
||||
use seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro_client::requests::generate_video::generate_video::{BatchCount, GenerateVideoArgs, ModelType, Resolution};
|
||||
|
||||
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
@@ -22,6 +22,7 @@ pub (crate) fn estimate_video_cost_artcraft_seedance2p0(
|
||||
|
||||
let args = GenerateVideoArgs {
|
||||
session: &dummy_session,
|
||||
model_type: ModelType::Seedance2Pro,
|
||||
prompt: String::new(),
|
||||
resolution: Resolution::Square1x1,
|
||||
duration_seconds,
|
||||
@@ -34,6 +35,7 @@ pub (crate) fn estimate_video_cost_artcraft_seedance2p0(
|
||||
reference_video_urls: None,
|
||||
reference_audio_urls: None,
|
||||
use_face_blur_hack: None,
|
||||
host_override: None,
|
||||
};
|
||||
|
||||
let cost_in_usd_cents = args.estimate_cost_in_usd_cents();
|
||||
@@ -95,9 +97,9 @@ mod tests {
|
||||
assert_eq!(estimate_usd_cents(5, 2), 160);
|
||||
assert_eq!(estimate_usd_cents(15, 2), 480);
|
||||
|
||||
// Batch 4 = 3× (not 4×)
|
||||
assert_eq!(estimate_usd_cents(4, 4), 192);
|
||||
assert_eq!(estimate_usd_cents(5, 4), 240);
|
||||
assert_eq!(estimate_usd_cents(15, 4), 720);
|
||||
// Batch 4 = 4×
|
||||
assert_eq!(estimate_usd_cents(4, 4), 256);
|
||||
assert_eq!(estimate_usd_cents(5, 4), 320);
|
||||
assert_eq!(estimate_usd_cents(15, 4), 960);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
use seedance2pro::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro::requests::generate_video::generate_video::{GenerateVideoArgs, Resolution};
|
||||
use seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro_client::requests::generate_video::generate_video::{GenerateVideoArgs, ModelType, Resolution};
|
||||
|
||||
use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
@@ -12,6 +12,7 @@ pub(crate) fn estimate_video_cost_seedance2pro_seedance2p0(
|
||||
|
||||
let args = GenerateVideoArgs {
|
||||
session: &dummy_session,
|
||||
model_type: ModelType::Seedance2Pro,
|
||||
prompt: String::new(),
|
||||
resolution: Resolution::Square1x1, // Resolution does not affect cost
|
||||
duration_seconds: plan.duration_seconds,
|
||||
@@ -22,6 +23,7 @@ pub(crate) fn estimate_video_cost_seedance2pro_seedance2p0(
|
||||
reference_video_urls: None,
|
||||
reference_audio_urls: None,
|
||||
use_face_blur_hack: None,
|
||||
host_override: None,
|
||||
};
|
||||
|
||||
let cost_in_credits = args.estimate_credits();
|
||||
|
||||
+11
-7
@@ -6,13 +6,13 @@ use crate::generate::generate_video::generate_video_response::{
|
||||
};
|
||||
use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0;
|
||||
use crate::utils::download_file::download_file;
|
||||
use seedance2pro::requests::generate_video::generate_video::{
|
||||
generate_video, GenerateVideoArgs,
|
||||
use seedance2pro_client::requests::generate_video::generate_video::{
|
||||
generate_video, GenerateVideoArgs, ModelType,
|
||||
};
|
||||
use seedance2pro::requests::prepare_file_upload::prepare_file_upload::{
|
||||
use seedance2pro_client::requests::prepare_file_upload::prepare_file_upload::{
|
||||
prepare_file_upload, PrepareFileUploadArgs,
|
||||
};
|
||||
use seedance2pro::requests::upload_file::upload_file::{
|
||||
use seedance2pro_client::requests::upload_file::upload_file::{
|
||||
upload_file, UploadFileArgs,
|
||||
};
|
||||
use url_utils::extension::extract_extension_from_url::{
|
||||
@@ -34,6 +34,7 @@ pub async fn execute_seedance2pro_seedance2p0(
|
||||
|
||||
let args = GenerateVideoArgs {
|
||||
session,
|
||||
model_type: ModelType::Seedance2Pro,
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
resolution: plan.resolution,
|
||||
duration_seconds: plan.duration_seconds,
|
||||
@@ -44,6 +45,7 @@ pub async fn execute_seedance2pro_seedance2p0(
|
||||
reference_video_urls,
|
||||
reference_audio_urls,
|
||||
use_face_blur_hack: None,
|
||||
host_override: None,
|
||||
};
|
||||
|
||||
let response = generate_video(args)
|
||||
@@ -58,7 +60,7 @@ pub async fn execute_seedance2pro_seedance2p0(
|
||||
|
||||
/// Downloads a file from a source URL and re-uploads it to seedance2pro CDN.
|
||||
async fn upload_to_seedance2pro(
|
||||
session: &seedance2pro::creds::seedance2pro_session::Seedance2ProSession,
|
||||
session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession,
|
||||
source_url: &str,
|
||||
) -> Result<String, ArtcraftRouterError> {
|
||||
let extension = extract_extension_from_url_str(source_url, &ExtractExtensions::All)
|
||||
@@ -70,6 +72,7 @@ async fn upload_to_seedance2pro(
|
||||
let prepare_response = prepare_file_upload(PrepareFileUploadArgs {
|
||||
session,
|
||||
extension,
|
||||
host_override: None,
|
||||
})
|
||||
.await
|
||||
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?;
|
||||
@@ -77,6 +80,7 @@ async fn upload_to_seedance2pro(
|
||||
let upload_response = upload_file(UploadFileArgs {
|
||||
upload_url: prepare_response.upload_url,
|
||||
file_bytes,
|
||||
host_override: None,
|
||||
})
|
||||
.await
|
||||
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?;
|
||||
@@ -85,7 +89,7 @@ async fn upload_to_seedance2pro(
|
||||
}
|
||||
|
||||
async fn upload_optional_url(
|
||||
session: &seedance2pro::creds::seedance2pro_session::Seedance2ProSession,
|
||||
session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession,
|
||||
url: Option<&str>,
|
||||
) -> Result<Option<String>, ArtcraftRouterError> {
|
||||
match url {
|
||||
@@ -95,7 +99,7 @@ async fn upload_optional_url(
|
||||
}
|
||||
|
||||
async fn upload_optional_url_list(
|
||||
session: &seedance2pro::creds::seedance2pro_session::Seedance2ProSession,
|
||||
session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession,
|
||||
urls: Option<&[String]>,
|
||||
) -> Result<Option<Vec<String>>, ArtcraftRouterError> {
|
||||
match urls {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
use seedance2pro::requests::generate_video::generate_video::{BatchCount, Resolution};
|
||||
use seedance2pro_client::requests::generate_video::generate_video::{BatchCount, Resolution};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanSeedance2proSeedance2p0 {
|
||||
|
||||
@@ -16,13 +16,13 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
# cargo-hakari workspace hack (faster compile times)
|
||||
workspace-build-acceleration.workspace = true
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../lib/bucket_paths" }
|
||||
bucket_paths.workspace = true
|
||||
crockford.workspace = true
|
||||
easyenv = { path = "../../lib/easyenv" }
|
||||
easyenv.workspace = true
|
||||
errors.workspace = true
|
||||
filesys.workspace = true
|
||||
hashing = { path = "../../lib/files/hashing" }
|
||||
@@ -31,12 +31,11 @@ storyteller_root = { path = "../../lib/storyteller_root" }
|
||||
|
||||
# External
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
env_logger = "0.11.3"
|
||||
async-trait = "0.1.75"
|
||||
env_logger.workspace = true
|
||||
log.workspace = true
|
||||
tokio.workspace = true
|
||||
|
||||
# The "never-encode-slash" feature seems to have been removed:
|
||||
# https://github.com/durch/rust-s3/pull/254
|
||||
rust-s3 = { version = "0.36.0-beta.2", default-features = false, features = ["fail-on-err", "tags", "tokio-rustls-tls"] }
|
||||
|
||||
# Runtime
|
||||
tokio.workspace = true
|
||||
rust-s3.workspace = true
|
||||
|
||||
@@ -12,7 +12,7 @@ name = "fal_client"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
# cargo-hakari workspace hack (faster compile times)
|
||||
workspace-build-acceleration.workspace = true
|
||||
|
||||
# Internal
|
||||
@@ -25,15 +25,16 @@ futures.workspace = true
|
||||
log.workspace = true
|
||||
reqwest.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
strum.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
# For now, we'll vendor in fal.
|
||||
# We need to implement webhooks and the upstream doesn't support them yet.
|
||||
#fal = { version = "0.3.6", features = ["endpoints"] }
|
||||
fal = { path = "../../vendor/fal-rs", features = ["endpoints"] }
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path = "../../lib/testing" }
|
||||
# Internal Dev
|
||||
test_utils.workspace = true
|
||||
test_data.workspace = true
|
||||
|
||||
# External Dev
|
||||
# (None yet)
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
use crate::error::fal_error::FalError;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
|
||||
const BILLING_ERROR : &str = "{\"detail\": \"User is locked. Reason: Exhausted balance. Top up your balance at fal.ai/dashboard/billing.\"}";
|
||||
|
||||
/// Better classify the `fal::FalError` into a more user-friendly `FalErrorPlus`.
|
||||
pub fn classify_fal_error(err: fal::FalError) -> FalErrorPlus {
|
||||
// Other("{\"detail\": \"User is locked. Reason: Exhausted balance. Top up your balance at fal.ai/dashboard/billing.\"}")
|
||||
/// Better classify the `FalError` into a more user-friendly `FalErrorPlus`.
|
||||
pub fn classify_fal_error(err: FalError) -> FalErrorPlus {
|
||||
match err {
|
||||
fal::FalError::RequestError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::ImageError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::SerializeError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::StreamError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::Other(ref inner) => {
|
||||
FalError::RequestError(_) => FalErrorPlus::FalError(err),
|
||||
FalError::SerializeError(_) => FalErrorPlus::FalError(err),
|
||||
FalError::Other(ref inner) => {
|
||||
if inner == BILLING_ERROR {
|
||||
FalErrorPlus::FalBillingError(inner.to_string())
|
||||
} else if inner.contains("billing") {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/// Error type for Fal API interactions.
|
||||
///
|
||||
/// Originally from the vendored `fal` crate (`fal::FalError`).
|
||||
/// Copied here so `fal_client` can be independent of the vendored crate.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FalError {
|
||||
#[error("fal request failed: {0}")]
|
||||
RequestError(#[from] reqwest::Error),
|
||||
|
||||
#[error("serialization error: {0}")]
|
||||
SerializeError(#[from] serde_json::Error),
|
||||
|
||||
#[error("error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<String> for FalError {
|
||||
fn from(s: String) -> Self {
|
||||
FalError::Other(s)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error::FalError;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
/// Additional errors that aren't included in `fal::FalError`.
|
||||
/// Additional errors that aren't included in `crate::error::fal_error::FalError`.
|
||||
#[derive(Debug)]
|
||||
pub enum FalErrorPlus {
|
||||
/// An error arising in the `fal` crate.
|
||||
FalError(fal::FalError),
|
||||
FalError(crate::error::fal_error::FalError),
|
||||
/// The fal API key is invalid.
|
||||
FalApiKeyError(String),
|
||||
/// The fal account has a billing issue
|
||||
@@ -37,8 +38,8 @@ impl Display for FalErrorPlus {
|
||||
|
||||
impl Error for FalErrorPlus {}
|
||||
|
||||
impl From<fal::FalError> for FalErrorPlus {
|
||||
fn from(err: fal::FalError) -> Self {
|
||||
impl From<FalError> for FalErrorPlus {
|
||||
fn from(err: FalError) -> Self {
|
||||
classify_fal_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod classify_fal_error;
|
||||
pub mod fal_error;
|
||||
pub mod fal_error_plus;
|
||||
@@ -1,11 +1,4 @@
|
||||
//! A wrapper for the "fal" crate that bakes in a few extra recipes and utilities.
|
||||
|
||||
extern crate fal;
|
||||
|
||||
// Re-export
|
||||
pub mod export {
|
||||
pub use fal::*;
|
||||
}
|
||||
//! A fal wrapper
|
||||
|
||||
pub mod creds;
|
||||
pub mod error;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::model::fal_endpoint::FalEndpoint;
|
||||
use crate::model::fal_request_id::FalRequestId;
|
||||
use crate::requests::api::queue::Queue;
|
||||
use crate::requests::api::queue_response::QueueResponse;
|
||||
use errors::AnyhowResult;
|
||||
use fal::queue::{Queue, QueueResponse};
|
||||
use reqwest::Client;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use fal::queue::Queue;
|
||||
use crate::requests::api::queue::Queue;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
// TODO(bt,2025-05-26): A macro to define these + tests.
|
||||
|
||||
const FLUX_PRO_ULTRA_TEXT_TO_IMAGE: &str = "fal-ai/flux-pro/v1.1-ultra";
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use reqwest::IntoUrl;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use log::info;
|
||||
|
||||
use crate::error::fal_error::FalError;
|
||||
use crate::requests::api::queue::Queue;
|
||||
use crate::requests::api::queue_response::QueueResponse;
|
||||
use crate::requests::api::webhook_response::WebhookResponse;
|
||||
|
||||
/// A request to the FAL API.
|
||||
///
|
||||
/// Originally from the vendored `fal` crate (`fal::request::FalRequest`).
|
||||
/// Copied here so `fal_client` can be independent of the vendored crate.
|
||||
#[derive(Debug)]
|
||||
pub struct FalRequest<Params: Serialize, Response: DeserializeOwned> {
|
||||
/// The Reqwest Client to use to make requests
|
||||
pub client: reqwest::Client,
|
||||
/// The endpoint to make the request to
|
||||
pub endpoint: String,
|
||||
/// The parameters to send to the endpoint
|
||||
pub params: Params,
|
||||
/// The API key to use to make the request.
|
||||
/// If not provided, the `FAL_API_KEY` environment variable will be used.
|
||||
pub api_key: Option<String>,
|
||||
phantom: PhantomData<Response>,
|
||||
}
|
||||
|
||||
impl<Params: Serialize, Response: DeserializeOwned> FalRequest<Params, Response> {
|
||||
pub fn new(endpoint: impl Into<String>, params: Params) -> Self {
|
||||
Self {
|
||||
client: reqwest::Client::new(),
|
||||
endpoint: endpoint.into(),
|
||||
params,
|
||||
api_key: std::env::var("FAL_API_KEY").ok(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Use a specific Reqwest Client to make requests
|
||||
pub fn with_client(mut self, client: reqwest::Client) -> Self {
|
||||
self.client = client;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use a specific API key to make requests
|
||||
pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
|
||||
self.api_key = Some(api_key.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Send the request and wait for the response
|
||||
pub async fn send(self) -> Result<Response, FalError> {
|
||||
let response = self
|
||||
.client
|
||||
.post(format!("https://fal.run/{}", self.endpoint))
|
||||
.json(&self.params)
|
||||
.header(
|
||||
"Authorization",
|
||||
format!(
|
||||
"Key {}",
|
||||
self.api_key.expect(
|
||||
"No fal API key provided, and FAL_API_KEY environment variable is not set"
|
||||
)
|
||||
),
|
||||
)
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status() != 200 {
|
||||
let error = response.text().await?;
|
||||
return Err(error.into());
|
||||
}
|
||||
|
||||
Ok(response.error_for_status()?.json().await?)
|
||||
}
|
||||
|
||||
/// Submit the request to the Fal queue system.
|
||||
pub async fn queue(self) -> Result<Queue<Response>, FalError> {
|
||||
let key = self
|
||||
.api_key
|
||||
.expect("No fal API key provided, and FAL_API_KEY environment variable is not set");
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.post(format!("https://queue.fal.run/{}", self.endpoint))
|
||||
.json(&self.params)
|
||||
.header("Authorization", format!("Key {}", &key))
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status() != 200 {
|
||||
let error = response.text().await?;
|
||||
return Err(error.into());
|
||||
}
|
||||
|
||||
let payload: QueueResponse = response.error_for_status()?.json().await?;
|
||||
|
||||
Ok(Queue::new(self.client, self.endpoint, key, payload))
|
||||
}
|
||||
|
||||
/// Submit the request to the Fal queue with a webhook callback URL.
|
||||
pub async fn queue_webhook<U: IntoUrl>(self, url: U) -> Result<WebhookResponse, FalError> {
|
||||
let key = self
|
||||
.api_key
|
||||
.expect("No fal API key provided, and FAL_API_KEY environment variable is not set");
|
||||
|
||||
let url_encoded = url.into_url()?;
|
||||
|
||||
let request_url = format!("https://queue.fal.run/{}?fal_webhook={}", self.endpoint, url_encoded);
|
||||
|
||||
info!("Sending request to FAL queue webhook: {}", request_url);
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.post(request_url)
|
||||
.json(&self.params)
|
||||
.header("Authorization", format!("Key {}", &key))
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status() != 200 {
|
||||
let error = response.text().await?;
|
||||
return Err(error.into());
|
||||
}
|
||||
|
||||
let payload: WebhookResponse = response.error_for_status()?.json().await?;
|
||||
|
||||
Ok(payload)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod fal_request;
|
||||
pub mod queue;
|
||||
pub mod queue_response;
|
||||
pub mod queue_status;
|
||||
pub mod webhook_response;
|
||||
@@ -0,0 +1,86 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
use crate::error::fal_error::FalError;
|
||||
use crate::requests::api::queue_response::QueueResponse;
|
||||
use crate::requests::api::queue_status::QueueStatus;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Queue<Response: DeserializeOwned> {
|
||||
#[serde(skip)]
|
||||
pub client: Option<reqwest::Client>,
|
||||
pub endpoint: String,
|
||||
pub api_key: String,
|
||||
pub payload: QueueResponse,
|
||||
phantom: PhantomData<Response>,
|
||||
}
|
||||
|
||||
impl<Response: DeserializeOwned> Queue<Response> {
|
||||
pub fn new(
|
||||
client: reqwest::Client,
|
||||
endpoint: impl Into<String>,
|
||||
api_key: String,
|
||||
payload: QueueResponse,
|
||||
) -> Self {
|
||||
Self {
|
||||
client: Some(client),
|
||||
endpoint: endpoint.into(),
|
||||
api_key,
|
||||
payload,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the status of the Queue request
|
||||
pub async fn status(&self, show_logs: bool) -> Result<QueueStatus, FalError> {
|
||||
let response = self
|
||||
.client
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&self.payload.status_url)
|
||||
.query(&[("logs", if show_logs { "1" } else { "0" })])
|
||||
.header("Authorization", format!("Key {}", self.api_key))
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
Ok(response.error_for_status()?.json().await?)
|
||||
}
|
||||
|
||||
/// Get the response of the Queue request, if the request is Completed
|
||||
pub async fn response(&self) -> Result<Response, FalError> {
|
||||
let response = self
|
||||
.client
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&self.payload.response_url)
|
||||
.header("Authorization", format!("Key {}", self.api_key))
|
||||
.header("Content-Type", "application/json")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status() != 200 {
|
||||
let error = response.text().await?;
|
||||
return Err(error.into());
|
||||
}
|
||||
|
||||
Ok(response.error_for_status()?.json().await?)
|
||||
}
|
||||
|
||||
/// Cancel the Queue request
|
||||
pub async fn cancel(&self) -> Result<(), FalError> {
|
||||
let response = self
|
||||
.client
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.put(&self.payload.cancel_url)
|
||||
.header("Authorization", format!("Key {}", self.api_key))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
response.error_for_status()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct QueueResponse {
|
||||
pub request_id: String,
|
||||
pub response_url: String,
|
||||
pub status_url: String,
|
||||
pub cancel_url: String,
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum Status {
|
||||
InQueue,
|
||||
InProgress,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RequestLog {
|
||||
pub timestamp: String,
|
||||
pub level: Option<String>,
|
||||
pub source: Option<String>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct QueueStatus {
|
||||
/// The status of the Queue request
|
||||
pub status: Status,
|
||||
/// The position of the request in the queue
|
||||
pub queue_position: Option<i64>,
|
||||
/// The URL of the response
|
||||
pub response_url: String,
|
||||
/// The logs of the request, if `show_logs` is `true`
|
||||
pub logs: Option<Vec<RequestLog>>,
|
||||
}
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
|
||||
use crate::prelude::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct WebhookResponse {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct RembgRemoveBackgroundInput {
|
||||
pub image_url: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub crop_to_bbox: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RembgRemoveBackgroundFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RembgRemoveBackgroundOutput {
|
||||
pub image: RembgRemoveBackgroundFile,
|
||||
}
|
||||
|
||||
pub fn rembg_remove_background(
|
||||
params: RembgRemoveBackgroundInput,
|
||||
) -> FalRequest<RembgRemoveBackgroundInput, RembgRemoveBackgroundOutput> {
|
||||
FalRequest::new("fal-ai/imageutils/rembg", params)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod http_rembg_remove_background;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct FluxProKontextMaxEditInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_url: String,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
/// "png" or "jpeg"
|
||||
/// Default: "jpeg"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
/// Aspect ratio for the generated image.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
|
||||
/// The safety tolerance level for content moderation.
|
||||
/// "1" (most strict) to "5" (most permissive).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub safety_tolerance: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxProKontextMaxEditFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxProKontextMaxEditOutput {
|
||||
pub images: Vec<FluxProKontextMaxEditFile>,
|
||||
}
|
||||
|
||||
pub fn flux_pro_kontext_max_edit(
|
||||
params: FluxProKontextMaxEditInput,
|
||||
) -> FalRequest<FluxProKontextMaxEditInput, FluxProKontextMaxEditOutput> {
|
||||
FalRequest::new("fal-ai/flux-pro/kontext/max", params)
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Gemini25FlashEditInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg" or "png"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
/// Aspect ratio for the generated image.
|
||||
/// Options: auto, 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Default: "auto"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Gemini25FlashEditFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Gemini25FlashEditOutput {
|
||||
pub images: Vec<Gemini25FlashEditFile>,
|
||||
}
|
||||
|
||||
pub fn gemini_25_flash_edit(
|
||||
params: Gemini25FlashEditInput,
|
||||
) -> FalRequest<Gemini25FlashEditInput, Gemini25FlashEditOutput> {
|
||||
FalRequest::new("fal-ai/gemini-25-flash-image/edit", params)
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct GptImage1EditImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// "auto", "1024x1024", "1536x1024", "1024x1536"
|
||||
pub image_size: String,
|
||||
|
||||
/// 1 - 4
|
||||
pub num_images: u8,
|
||||
|
||||
/// "auto", "low", "medium", "high"
|
||||
pub quality: String,
|
||||
|
||||
/// BYOK - caller supplies their own OpenAI API key
|
||||
pub openai_api_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1EditImageOutput {
|
||||
// Response fields parsed elsewhere
|
||||
}
|
||||
|
||||
pub fn gpt_image_1_edit_image(
|
||||
params: GptImage1EditImageInput,
|
||||
) -> FalRequest<GptImage1EditImageInput, GptImage1EditImageOutput> {
|
||||
FalRequest::new("fal-ai/gpt-image-1/edit-image/byok", params)
|
||||
}
|
||||
+19
-18
@@ -1,53 +1,54 @@
|
||||
use crate::prelude::{Deserialize, FalRequest, Serialize};
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct GptImage1p5ImageEditInput {
|
||||
pub struct GptImage1p5EditImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// The URL of the mask image to use for the generation. This indicates what part of the image to edit.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mask_image_url: Option<String>,
|
||||
|
||||
/// Eg. auto, 1024x1024, 1536x1024, 1024x1536
|
||||
/// "auto", "1024x1024", "1536x1024", "1024x1536"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// Eg. Possible enum values: auto, transparent, opaque
|
||||
/// "auto", "transparent", "opaque"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub background: Option<String>,
|
||||
|
||||
/// Eg. Possible enum values: low, medium, high
|
||||
/// "low", "medium", "high"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub quality: Option<String>,
|
||||
|
||||
/// Eg. Possible enum values: low, high
|
||||
/// "low", "high"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub input_fidelity: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// Possible enum values: jpeg, png, webp
|
||||
/// "jpeg", "png", "webp"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1p5ImageEditOutput {
|
||||
pub images: Vec<ImageFile>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct ImageFile {
|
||||
/// The URL where the file can be downloaded from.
|
||||
pub struct GptImage1p5EditImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub fn gpt_image_1p5_image_edit(
|
||||
params: GptImage1p5ImageEditInput,
|
||||
) -> FalRequest<GptImage1p5ImageEditInput, GptImage1p5ImageEditOutput> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1p5EditImageOutput {
|
||||
pub images: Vec<GptImage1p5EditImageFile>,
|
||||
}
|
||||
|
||||
pub fn gpt_image_1p5_edit_image(
|
||||
params: GptImage1p5EditImageInput,
|
||||
) -> FalRequest<GptImage1p5EditImageInput, GptImage1p5EditImageOutput> {
|
||||
FalRequest::new("fal-ai/gpt-image-1.5/edit", params)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct NanoBananaProEditImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// Eg. "auto", "16:9", "1:1", etc.
|
||||
/// Options: auto, 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Default: "auto"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
|
||||
/// Eg. "1K", "2K", "4K"
|
||||
/// Default: "1K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolution: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg", "png", "webp"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProEditImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProEditImageOutput {
|
||||
pub images: Vec<NanoBananaProEditImageFile>,
|
||||
}
|
||||
|
||||
pub fn nano_banana_pro_edit_image(
|
||||
params: NanoBananaProEditImageInput,
|
||||
) -> FalRequest<NanoBananaProEditImageInput, NanoBananaProEditImageOutput> {
|
||||
FalRequest::new("fal-ai/nano-banana-pro/edit", params)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct QwenImageEditInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_url: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg" or "png"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub negative_prompt: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<u64>,
|
||||
|
||||
/// Default: 30
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<u8>,
|
||||
|
||||
/// Default: 4.0
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
/// Default: true
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
/// Options: "none", "regular", "high"
|
||||
/// Default: "none"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub acceleration: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct QwenImageEditFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct QwenImageEditOutput {
|
||||
pub images: Vec<QwenImageEditFile>,
|
||||
}
|
||||
|
||||
pub fn qwen_image_edit(
|
||||
params: QwenImageEditInput,
|
||||
) -> FalRequest<QwenImageEditInput, QwenImageEditOutput> {
|
||||
FalRequest::new("fal-ai/qwen-image-edit", params)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct SeedEditV3EditInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_url: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedEditV3EditFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedEditV3EditOutput {
|
||||
pub image: Vec<SeedEditV3EditFile>,
|
||||
}
|
||||
|
||||
pub fn seededit_v3_edit(
|
||||
params: SeedEditV3EditInput,
|
||||
) -> FalRequest<SeedEditV3EditInput, SeedEditV3EditOutput> {
|
||||
FalRequest::new("fal-ai/bytedance/seededit/v3/edit-image", params)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct SeedreamV4EditImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Maximum 10 images. Excess images are ignored.
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9, auto, auto_2K, auto_4K
|
||||
/// Default: "auto_2K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_images: Option<u8>,
|
||||
|
||||
/// Enum: "standard", "fast"
|
||||
/// Default: "standard"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enhance_prompt_mode: Option<String>,
|
||||
|
||||
/// Default: true
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4EditImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4EditImageOutput {
|
||||
pub images: Vec<SeedreamV4EditImageFile>,
|
||||
}
|
||||
|
||||
pub fn seedream_4_edit_image(
|
||||
params: SeedreamV4EditImageInput,
|
||||
) -> FalRequest<SeedreamV4EditImageInput, SeedreamV4EditImageOutput> {
|
||||
FalRequest::new("fal-ai/bytedance/seedream/v4/edit", params)
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct SeedreamV4p5EditImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Maximum 10 images. Excess images are ignored.
|
||||
pub image_urls: Vec<String>,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9, auto_2K, auto_4K
|
||||
/// Default: "auto_2K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_images: Option<u8>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
/// Default: true
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4p5EditImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4p5EditImageOutput {
|
||||
pub images: Vec<SeedreamV4p5EditImageFile>,
|
||||
}
|
||||
|
||||
pub fn seedream_4p5_edit_image(
|
||||
params: SeedreamV4p5EditImageInput,
|
||||
) -> FalRequest<SeedreamV4p5EditImageInput, SeedreamV4p5EditImageOutput> {
|
||||
FalRequest::new("fal-ai/bytedance/seedream/v4.5/edit", params)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
@@ -0,0 +1,11 @@
|
||||
pub mod http_flux_pro_kontext_max_edit;
|
||||
pub mod http_gemini_25_flash_edit;
|
||||
pub mod http_gpt_image_1_edit_image;
|
||||
pub mod http_gpt_image_1p5_edit_image;
|
||||
pub mod http_nano_banana_2_edit_image;
|
||||
pub mod http_nano_banana_pro_edit_image;
|
||||
pub mod http_qwen_image_edit;
|
||||
pub mod http_seedream_4_edit_image;
|
||||
pub mod http_seedream_4p5_edit_image;
|
||||
pub mod http_seedream_5_edit_image;
|
||||
pub mod http_seededit_v3_edit;
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct FluxDevJuggernautInfillInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_url: String,
|
||||
|
||||
pub mask_url: String,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
/// "png" or "jpeg"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
/// 0.0 - 1.0. 1.0 completely remakes the image, 0.0 preserves the original.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub strength: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<i64>,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxDevJuggernautInfillFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxDevJuggernautInfillOutput {
|
||||
pub images: Vec<FluxDevJuggernautInfillFile>,
|
||||
}
|
||||
|
||||
pub fn flux_dev_juggernaut_infill(
|
||||
params: FluxDevJuggernautInfillInput,
|
||||
) -> FalRequest<FluxDevJuggernautInfillInput, FluxDevJuggernautInfillOutput> {
|
||||
FalRequest::new("rundiffusion-fal/juggernaut-flux-lora/inpainting", params)
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct FluxPro1InfillInput {
|
||||
pub prompt: String,
|
||||
|
||||
pub image_url: String,
|
||||
|
||||
pub mask_url: String,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
/// "1" (most strict) to "5" (most permissive)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub safety_tolerance: Option<String>,
|
||||
|
||||
/// "png" or "jpeg"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro1InfillFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro1InfillOutput {
|
||||
pub images: Vec<FluxPro1InfillFile>,
|
||||
}
|
||||
|
||||
pub fn flux_pro_1_infill(
|
||||
params: FluxPro1InfillInput,
|
||||
) -> FalRequest<FluxPro1InfillInput, FluxPro1InfillOutput> {
|
||||
FalRequest::new("fal-ai/flux-pro/v1/fill", params)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod http_flux_dev_juggernaut_infill;
|
||||
pub mod http_flux_pro_1_infill;
|
||||
@@ -1,5 +1,5 @@
|
||||
pub mod angle;
|
||||
pub mod http_nano_banana_2_edit_image;
|
||||
pub mod http_nano_banana_2_text_to_image;
|
||||
pub mod http_seedream_5_edit_image;
|
||||
pub mod http_seedream_5_text_to_image;
|
||||
pub mod background;
|
||||
pub mod edit;
|
||||
pub mod infill;
|
||||
pub mod text;
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Flux1DevTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Flux1DevTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Flux1DevTextToImageOutput {
|
||||
pub images: Vec<Flux1DevTextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn flux_1_dev_text_to_image(
|
||||
params: Flux1DevTextToImageInput,
|
||||
) -> FalRequest<Flux1DevTextToImageInput, Flux1DevTextToImageOutput> {
|
||||
FalRequest::new("fal-ai/flux/dev", params)
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Flux1SchnellTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Flux1SchnellTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Flux1SchnellTextToImageOutput {
|
||||
pub images: Vec<Flux1SchnellTextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn flux_1_schnell_text_to_image(
|
||||
params: Flux1SchnellTextToImageInput,
|
||||
) -> FalRequest<Flux1SchnellTextToImageInput, Flux1SchnellTextToImageOutput> {
|
||||
FalRequest::new("fal-ai/flux/schnell", params)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct FluxPro11TextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
/// "1" (most strict) to "5" (most permissive)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub safety_tolerance: Option<String>,
|
||||
|
||||
/// "png" or "jpeg"
|
||||
/// Default: "jpeg"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro11TextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro11TextToImageOutput {
|
||||
pub images: Vec<FluxPro11TextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn flux_pro_11_text_to_image(
|
||||
params: FluxPro11TextToImageInput,
|
||||
) -> FalRequest<FluxPro11TextToImageInput, FluxPro11TextToImageOutput> {
|
||||
FalRequest::new("fal-ai/flux-pro/v1.1", params)
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct FluxPro11UltraTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: 21:9, 16:9, 4:3, 3:2, 1:1, 2:3, 3:4, 9:16, 9:21
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
/// Generate less processed, more natural-looking images.
|
||||
/// Default: false
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub raw: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
|
||||
/// "1" (most strict) to "5" (most permissive)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub safety_tolerance: Option<String>,
|
||||
|
||||
/// "png" or "jpeg"
|
||||
/// Default: "jpeg"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sync_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro11UltraTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FluxPro11UltraTextToImageOutput {
|
||||
pub images: Vec<FluxPro11UltraTextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn flux_pro_11_ultra_text_to_image(
|
||||
params: FluxPro11UltraTextToImageInput,
|
||||
) -> FalRequest<FluxPro11UltraTextToImageInput, FluxPro11UltraTextToImageOutput> {
|
||||
FalRequest::new("fal-ai/flux-pro/v1.1-ultra", params)
|
||||
}
|
||||
+9
-8
@@ -1,33 +1,34 @@
|
||||
use crate::prelude::{Deserialize, FalRequest, Serialize};
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Gemini25FlashTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg" or "png"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
|
||||
/// The aspect ratio of the generated image.
|
||||
/// Default value: "1:1"
|
||||
/// Possible enum values: 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Options: 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Default: "1:1"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct File {
|
||||
/// The URL where the file can be downloaded from.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Gemini25FlashTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Gemini25FlashTextToImageOutput {
|
||||
pub images: Vec<File>,
|
||||
pub images: Vec<Gemini25FlashTextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn gemini_25_flash_text_to_image(
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct GptImage1TextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// "auto", "1024x1024", "1536x1024", "1024x1536"
|
||||
pub image_size: String,
|
||||
|
||||
/// 1 - 4
|
||||
pub num_images: u8,
|
||||
|
||||
/// "auto", "low", "medium", "high"
|
||||
pub quality: String,
|
||||
|
||||
/// BYOK - caller supplies their own OpenAI API key
|
||||
pub openai_api_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1TextToImageOutput {
|
||||
// Response fields parsed elsewhere
|
||||
}
|
||||
|
||||
pub fn gpt_image_1_text_to_image(
|
||||
params: GptImage1TextToImageInput,
|
||||
) -> FalRequest<GptImage1TextToImageInput, GptImage1TextToImageOutput> {
|
||||
FalRequest::new("fal-ai/gpt-image-1/text-to-image/byok", params)
|
||||
}
|
||||
+11
-9
@@ -1,39 +1,41 @@
|
||||
use crate::prelude::{Deserialize, FalRequest, Serialize};
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct GptImage1p5TextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Eg. auto, 1024x1024, 1536x1024, 1024x1536
|
||||
/// "auto", "1024x1024", "1536x1024", "1024x1536"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// Eg. Possible enum values: auto, transparent, opaque
|
||||
/// "auto", "transparent", "opaque"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub background: Option<String>,
|
||||
|
||||
/// Eg. Possible enum values: low, medium, high
|
||||
/// "low", "medium", "high"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub quality: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// Possible enum values: jpeg, png, webp
|
||||
/// "jpeg", "png", "webp"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct ImageFile {
|
||||
/// The URL where the file can be downloaded from.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1p5TextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GptImage1p5TextToImageOutput {
|
||||
pub images: Vec<ImageFile>,
|
||||
pub images: Vec<GptImage1p5TextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn gpt_image_1p5_text_to_image(
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
+11
-7
@@ -1,35 +1,39 @@
|
||||
use crate::prelude::{Deserialize, FalRequest, Serialize};
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct NanoBananaProTextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Eg. "16:9", "1:1", and a ton of other options. So many options.
|
||||
/// Options: auto, 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16
|
||||
/// Default: "auto"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub aspect_ratio: Option<String>,
|
||||
|
||||
/// Eg. "1K", "2K", "4K"
|
||||
/// "1K", "2K", "4K"
|
||||
/// Default: "1K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resolution: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// "jpeg", "png", "webp"
|
||||
/// Default: "png"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct ImageFile {
|
||||
/// The URL where the file can be downloaded from.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProTextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NanoBananaProTextToImageOutput {
|
||||
pub images: Vec<ImageFile>,
|
||||
pub images: Vec<NanoBananaProTextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn nano_banana_pro_text_to_image(
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct SeedreamV4TextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9, auto, auto_2K, auto_4K
|
||||
/// Default: "auto_2K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_images: Option<u8>,
|
||||
|
||||
/// Enum: "standard", "fast"
|
||||
/// Default: "standard"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enhance_prompt_mode: Option<String>,
|
||||
|
||||
/// Default: true
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4TextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4TextToImageOutput {
|
||||
pub images: Vec<SeedreamV4TextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn seedream_4_text_to_image(
|
||||
params: SeedreamV4TextToImageInput,
|
||||
) -> FalRequest<SeedreamV4TextToImageInput, SeedreamV4TextToImageOutput> {
|
||||
FalRequest::new("fal-ai/bytedance/seedream/v4/text-to-image", params)
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct SeedreamV4p5TextToImageInput {
|
||||
pub prompt: String,
|
||||
|
||||
/// Options: square_hd, square, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9, auto_2K, auto_4K
|
||||
/// Default: "auto_2K"
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_size: Option<String>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_images: Option<u8>,
|
||||
|
||||
/// 1 - 4
|
||||
/// Default: 1
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_images: Option<u8>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
|
||||
/// Default: true
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enable_safety_checker: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4p5TextToImageFile {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SeedreamV4p5TextToImageOutput {
|
||||
pub images: Vec<SeedreamV4p5TextToImageFile>,
|
||||
}
|
||||
|
||||
pub fn seedream_4p5_text_to_image(
|
||||
params: SeedreamV4p5TextToImageInput,
|
||||
) -> FalRequest<SeedreamV4p5TextToImageInput, SeedreamV4p5TextToImageOutput> {
|
||||
FalRequest::new("fal-ai/bytedance/seedream/v4.5/text-to-image", params)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use fal::request::FalRequest;
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
@@ -0,0 +1,12 @@
|
||||
pub mod http_flux_1_dev_text_to_image;
|
||||
pub mod http_flux_1_schnell_text_to_image;
|
||||
pub mod http_flux_pro_11_text_to_image;
|
||||
pub mod http_flux_pro_11_ultra_text_to_image;
|
||||
pub mod http_gemini_25_flash_text_to_image;
|
||||
pub mod http_gpt_image_1_text_to_image;
|
||||
pub mod http_gpt_image_1p5_text_to_image;
|
||||
pub mod http_nano_banana_2_text_to_image;
|
||||
pub mod http_nano_banana_pro_text_to_image;
|
||||
pub mod http_seedream_4_text_to_image;
|
||||
pub mod http_seedream_4p5_text_to_image;
|
||||
pub mod http_seedream_5_text_to_image;
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod image;
|
||||
pub mod object;
|
||||
pub mod video;
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Hunyuan3dV21ImageTo3dInput {
|
||||
pub input_image_url: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub textured_mesh: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub octree_resolution: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Hunyuan3dV21ImageTo3dOutput {}
|
||||
|
||||
pub fn hunyuan3d_v21_image_to_3d(
|
||||
params: Hunyuan3dV21ImageTo3dInput,
|
||||
) -> FalRequest<Hunyuan3dV21ImageTo3dInput, Hunyuan3dV21ImageTo3dOutput> {
|
||||
FalRequest::new("fal-ai/hunyuan3d-v21", params)
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
use crate::requests::api::fal_request::FalRequest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Hunyuan3dV2ImageTo3dInput {
|
||||
pub input_image_url: String,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub textured_mesh: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub guidance_scale: Option<f64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub num_inference_steps: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub octree_resolution: Option<i64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub seed: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Hunyuan3dV2ImageTo3dOutput {}
|
||||
|
||||
pub fn hunyuan3d_v2_image_to_3d(
|
||||
params: Hunyuan3dV2ImageTo3dInput,
|
||||
) -> FalRequest<Hunyuan3dV2ImageTo3dInput, Hunyuan3dV2ImageTo3dOutput> {
|
||||
FalRequest::new("fal-ai/hunyuan3d/v2", params)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user