mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 06:14:52 -05:00
Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3581d2c698 | ||
|
|
85c20cd3f9 | ||
|
|
bda1060a21 | ||
|
|
ed1c7fbc1b | ||
|
|
aded57c9a0 | ||
|
|
8032b79a4d | ||
|
|
9937efed81 | ||
|
|
8a2c4dc0e8 | ||
|
|
09e197d19a | ||
|
|
bfc34005d9 | ||
|
|
3543393965 | ||
|
|
d2d56d7220 | ||
|
|
25b2be92c8 | ||
|
|
89f6015e3f | ||
|
|
3b889b6fdb | ||
|
|
3ab2974d89 | ||
|
|
220cf66dfc | ||
|
|
2d18a07843 | ||
|
|
369c552096 | ||
|
|
13a5dad3a5 | ||
|
|
f8be6ea4c9 | ||
|
|
5f70776afe | ||
|
|
5c5a7d1182 | ||
|
|
d0e5a05253 | ||
|
|
72e052fe7e | ||
|
|
7471259d28 | ||
|
|
ffde0b06c0 | ||
|
|
b4da753346 | ||
|
|
312c603cef | ||
|
|
bdfa31421f | ||
|
|
c78442cf71 | ||
|
|
58b64b694c | ||
|
|
f666e68dcd | ||
|
|
5a7c253189 | ||
|
|
808beafd4c | ||
|
|
a10cda3bee | ||
|
|
40f884c776 | ||
|
|
9b6b0175ea | ||
|
|
a484b1d1a9 | ||
|
|
80d6866fd1 | ||
|
|
ac9a0c2172 | ||
|
|
03c3507841 | ||
|
|
7a7fa63fcc | ||
|
|
30cc15355a | ||
|
|
ee16d355f9 |
+135
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n jobs.token as `job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken`,\n\n jobs.status as `status: enums::common::job_status_plus::JobStatusPlus`,\n\n jobs.maybe_external_third_party as `external_third_party: enums::by_table::generic_inference_jobs::inference_job_external_third_party::InferenceJobExternalThirdParty`,\n jobs.maybe_external_third_party_id as `external_third_party_id`,\n\n jobs.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n jobs.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n jobs.creator_ip_address,\n\n jobs.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n jobs.maybe_debug_log_event_token as `maybe_debug_log_event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n\n jobs.created_at,\n jobs.updated_at\n\nFROM generic_inference_jobs as jobs\n\nWHERE jobs.maybe_external_third_party = ?\nAND jobs.maybe_external_third_party_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "status: enums::common::job_status_plus::JobStatusPlus",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 76
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "external_third_party: enums::by_table::generic_inference_jobs::inference_job_external_third_party::InferenceJobExternalThirdParty",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "external_third_party_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "maybe_debug_log_event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "31d85cc0013f29e6db2d272ee6e709cca79b46496a2c222960f1a1419175f00b"
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n id as `id: u64`,\n event_token as `event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,\n maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n message,\n created_at\nFROM debug_logs\nWHERE event_token = ?\nORDER BY id ASC\nLIMIT ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id: u64",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | PRIMARY_KEY | UNSIGNED | AUTO_INCREMENT",
|
||||
"char_set": 63,
|
||||
"max_size": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 96
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "message",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 67108860
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a62b88fec40a11952cc199383090ea338f97091e8bfc6b68aad67416685889af"
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n token as `token: tokens::tokens::generic_inference_jobs::InferenceJobToken`,\n uuid_idempotency_token,\n job_type as `maybe_job_type`,\n product_category as `maybe_product_category`,\n inference_category,\n maybe_external_third_party,\n maybe_external_third_party_id,\n maybe_model_type,\n maybe_model_token,\n maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n maybe_inference_args,\n maybe_download_url,\n on_success_result_entity_type,\n on_success_result_entity_token,\n on_success_result_batch_token,\n maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n maybe_creator_anonymous_visitor_token,\n creator_ip_address,\n creator_set_visibility,\n maybe_wallet_ledger_entry_token,\n maybe_debug_log_event_token as `maybe_debug_log_event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n status,\n attempt_count as `attempt_count: u16`,\n failure_reason,\n internal_debugging_failure_reason,\n frontend_failure_category,\n maybe_routing_tag,\n assigned_worker,\n assigned_cluster,\n created_at,\n updated_at\nFROM generic_inference_jobs\nWHERE token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::generic_inference_jobs::InferenceJobToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "uuid_idempotency_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 144
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "maybe_job_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "maybe_product_category",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "inference_category",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "maybe_external_third_party",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_external_third_party_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "maybe_model_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "maybe_model_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_inference_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "BLOB | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "maybe_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 4096
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "on_success_result_entity_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "on_success_result_entity_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "on_success_result_batch_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "maybe_creator_anonymous_visitor_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "creator_set_visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "maybe_wallet_ledger_entry_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "maybe_debug_log_event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "status",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 76
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "attempt_count: u16",
|
||||
"type_info": {
|
||||
"type": "Short",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "failure_reason",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "internal_debugging_failure_reason",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "frontend_failure_category",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"name": "maybe_routing_tag",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"name": "assigned_worker",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 512
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"name": "assigned_cluster",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 512
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e869f065e6f184abbabae04ecd0da6ea02c0576cc22ee55e47eb91dd34048ef1"
|
||||
}
|
||||
Generated
+17
@@ -1404,6 +1404,22 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beeble_client"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"errors",
|
||||
"log",
|
||||
"reqwest 0.12.23",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"test_data",
|
||||
"tokio",
|
||||
"workspace-build-acceleration",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bigdecimal"
|
||||
version = "0.3.1"
|
||||
@@ -11234,6 +11250,7 @@ dependencies = [
|
||||
"async-stripe 0.26.0",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"beeble_client",
|
||||
"billing_artcraft_component",
|
||||
"billing_component",
|
||||
"bootstrap",
|
||||
|
||||
@@ -16,6 +16,7 @@ members = [
|
||||
"crates/api_clients/grok_client",
|
||||
"crates/api_clients/midjourney_client",
|
||||
"crates/api_clients/muapi_client",
|
||||
"crates/api_clients/beeble_client",
|
||||
"crates/api_clients/openai_sora_client",
|
||||
"crates/api_clients/openart_client",
|
||||
"crates/api_clients/rootly_client",
|
||||
@@ -244,6 +245,7 @@ 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" }
|
||||
beeble_client = { path = "crates/api_clients/beeble_client" }
|
||||
grok_client = { path = "crates/api_clients/grok_client" }
|
||||
rootly_client = { path = "crates/api_clients/rootly_client" }
|
||||
rootly_config = { path = "crates/schema/config/rootly_config" }
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
$kind: collection
|
||||
name: edit
|
||||
order: 312
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
$kind: http-request
|
||||
name: Beeble SwitchX Edit Video
|
||||
url: "{{api_host}}/v1/generate/video/edit/beeble_switchx"
|
||||
method: POST
|
||||
headers:
|
||||
- key: Accept
|
||||
value: application/json
|
||||
- key: Session
|
||||
value: ""
|
||||
disabled: true
|
||||
body:
|
||||
type: json
|
||||
content: >-
|
||||
{
|
||||
"uuid_idempotency_token": "{{$randomUUID}}",
|
||||
//"source_video_media_token": "m_6vve5gffn2r4rajyvy8z2380x15kqc", // two corgis (dev)
|
||||
"source_video_media_token": "m_rkgdk7qw0a7gz4mrzfv0q78ax57kbx", // corgi cowboy (dev)
|
||||
//"source_video_media_token": "m_1k19k6dgdny253zag8g3jqf3bgemss", // corgi watermellon (prod)
|
||||
"reference_image_media_token": "m_pf310vdhc4v98n7r8mz70bz9geest3" // tornado (dev)
|
||||
//"reference_image_media_token": "m_z4y097t9pdmbyatf70z0qb8zvfphvm" // cactus (prod)
|
||||
//"prompt": "Stormy skies, there's a rotating tornado in the background"
|
||||
}
|
||||
order: 1778262498846
|
||||
@@ -9,7 +9,7 @@ body:
|
||||
// hanashi : password (dev)
|
||||
//"username_or_email": "hanashi",
|
||||
//"password": "hanashi"
|
||||
"username_or_email": "newuser2",
|
||||
"password": "newuser2"
|
||||
"username_or_email": "newuser4",
|
||||
"password": "newuser4"
|
||||
}
|
||||
order: 1000
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const BEEBLE_SWITCHX_EDIT_VIDEO_PATH: &str = "/v1/generate/video/edit/beeble_switchx";
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct BeebleSwitchXEditVideoRequest {
|
||||
pub uuid_idempotency_token: String,
|
||||
pub source_video_media_token: Option<MediaFileToken>,
|
||||
pub reference_image_media_token: Option<MediaFileToken>,
|
||||
pub prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct BeebleSwitchXEditVideoResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod beeble_switchx_edit_video;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod edit;
|
||||
pub mod generate_kling_1_6_pro_image_to_video;
|
||||
pub mod generate_kling_2_1_master_image_to_video;
|
||||
pub mod generate_kling_2_1_pro_image_to_video;
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use crate::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::error::storyteller_error::StorytellerError;
|
||||
use crate::utils::api_host::ApiHost;
|
||||
use crate::utils::basic_json_post_request::basic_json_post_request;
|
||||
use artcraft_api_defs::generate::video::edit::beeble_switchx_edit_video::{
|
||||
BeebleSwitchXEditVideoRequest, BeebleSwitchXEditVideoResponse, BEEBLE_SWITCHX_EDIT_VIDEO_PATH,
|
||||
};
|
||||
|
||||
pub async fn beeble_switchx_edit_video(
|
||||
api_host: &ApiHost,
|
||||
maybe_creds: Option<&StorytellerCredentialSet>,
|
||||
request: BeebleSwitchXEditVideoRequest,
|
||||
) -> Result<BeebleSwitchXEditVideoResponse, StorytellerError> {
|
||||
Ok(basic_json_post_request(
|
||||
api_host,
|
||||
BEEBLE_SWITCHX_EDIT_VIDEO_PATH,
|
||||
maybe_creds,
|
||||
request,
|
||||
).await?)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod beeble_switchx_edit_video;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod edit;
|
||||
pub mod generate_kling_16_pro_image_to_video;
|
||||
pub mod generate_kling_21_master_image_to_video;
|
||||
pub mod generate_kling_21_pro_image_to_video;
|
||||
|
||||
@@ -5,5 +5,6 @@ pub mod request_mismatch_mitigation_strategy;
|
||||
pub mod router_artcraft_client;
|
||||
pub mod router_client;
|
||||
pub mod router_fal_client;
|
||||
pub mod router_fal_webhook_optional_client;
|
||||
pub mod router_muapi_client;
|
||||
pub mod router_seedance2pro_client;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
@@ -7,6 +8,7 @@ use crate::errors::client_error::{ClientError, ClientType};
|
||||
pub struct MultiRouterClient {
|
||||
pub(crate) artcraft_client: Option<RouterArtcraftClient>,
|
||||
pub(crate) fal_client: Option<RouterFalClient>,
|
||||
pub(crate) fal_webhook_optional_client: Option<RouterFalWebhookOptionalClient>,
|
||||
pub(crate) muapi_client: Option<RouterMuapiClient>,
|
||||
pub(crate) seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
}
|
||||
@@ -21,6 +23,10 @@ impl MultiRouterClient {
|
||||
self.fal_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::Fal))
|
||||
}
|
||||
pub fn get_fal_webhook_optional_client_ref(&self) -> Result<&RouterFalWebhookOptionalClient, ClientError> {
|
||||
self.fal_webhook_optional_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::FalWebhookOptional))
|
||||
}
|
||||
|
||||
pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> {
|
||||
self.muapi_client.as_ref()
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use crate::client::multi_router_client::MultiRouterClient;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
|
||||
pub struct MultiRouterClientBuilder {
|
||||
artcraft_client: Option<RouterArtcraftClient>,
|
||||
fal_client: Option<RouterFalClient>,
|
||||
fal_webhook_optional_client: Option<RouterFalWebhookOptionalClient>,
|
||||
muapi_client: Option<RouterMuapiClient>,
|
||||
seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
}
|
||||
@@ -16,6 +18,7 @@ impl MultiRouterClientBuilder {
|
||||
Self {
|
||||
artcraft_client: None,
|
||||
fal_client: None,
|
||||
fal_webhook_optional_client: None,
|
||||
muapi_client: None,
|
||||
seedance2pro_client: None,
|
||||
}
|
||||
@@ -30,6 +33,11 @@ impl MultiRouterClientBuilder {
|
||||
self.fal_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_fal_webhook_optional_client(mut self, client: RouterFalWebhookOptionalClient) -> Self {
|
||||
self.fal_webhook_optional_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_muapi_client(mut self, client: RouterMuapiClient) -> Self {
|
||||
self.muapi_client = Some(client);
|
||||
@@ -45,6 +53,7 @@ impl MultiRouterClientBuilder {
|
||||
MultiRouterClient {
|
||||
artcraft_client: self.artcraft_client,
|
||||
fal_client: self.fal_client,
|
||||
fal_webhook_optional_client: self.fal_webhook_optional_client,
|
||||
muapi_client: self.muapi_client,
|
||||
seedance2pro_client: self.seedance2pro_client,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::client::multi_router_client::MultiRouterClient;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
@@ -9,6 +10,7 @@ pub enum RouterClient {
|
||||
Multi(MultiRouterClient),
|
||||
Artcraft(RouterArtcraftClient),
|
||||
Fal(RouterFalClient),
|
||||
FalWebhookOptional(RouterFalWebhookOptionalClient),
|
||||
Muapi(RouterMuapiClient),
|
||||
Seedance2Pro(RouterSeedance2ProClient),
|
||||
}
|
||||
@@ -30,6 +32,14 @@ impl RouterClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fal_webhook_optional_client_ref(&self) -> Result<&RouterFalWebhookOptionalClient, ClientError> {
|
||||
match self {
|
||||
RouterClient::FalWebhookOptional(client) => Ok(client),
|
||||
RouterClient::Multi(multi) => multi.get_fal_webhook_optional_client_ref(),
|
||||
_ => Err(ClientError::ClientNotConfigured(ClientType::Fal)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> {
|
||||
match self {
|
||||
RouterClient::Muapi(client) => Ok(client),
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
use fal_client::creds::fal_api_key::FalApiKey;
|
||||
|
||||
pub struct RouterFalWebhookOptionalClient {
|
||||
pub(crate) api_key: FalApiKey,
|
||||
pub(crate) webhook_url: Option<String>,
|
||||
}
|
||||
|
||||
impl RouterFalWebhookOptionalClient {
|
||||
pub fn new(api_key: FalApiKey) -> Self {
|
||||
Self { api_key, webhook_url: None }
|
||||
}
|
||||
|
||||
pub fn new_with_webhook(api_key: FalApiKey, webhook_url: String) -> Self {
|
||||
Self {
|
||||
api_key,
|
||||
webhook_url: Some(webhook_url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use tokens::tokens::media_files::MediaFileToken;
|
||||
pub enum ClientType {
|
||||
Artcraft,
|
||||
Fal,
|
||||
FalWebhookOptional,
|
||||
Muapi,
|
||||
Seedance2Pro,
|
||||
}
|
||||
@@ -16,6 +17,7 @@ impl Display for ClientType {
|
||||
match self {
|
||||
Self::Artcraft => write!(f, "Artcraft"),
|
||||
Self::Fal => write!(f, "Fal"),
|
||||
Self::FalWebhookOptional => write!(f, "FalWebhookOptional"),
|
||||
Self::Muapi => write!(f, "Muapi"),
|
||||
Self::Seedance2Pro => write!(f, "Seedance2Pro"),
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Flux1Dev,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -20,11 +20,11 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
#[test]
|
||||
fn test_estimate_cost_is_none() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Flux1Schnell,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -34,12 +34,12 @@ mod tests {
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let tokens = vec![MediaFileToken::new_from_str("test_token")];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Flux2LoraAngles,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -36,10 +36,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::FluxPro11,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::FluxPro11Ultra,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+5
-5
@@ -59,11 +59,11 @@ mod tests {
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
fn base() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage1,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
@@ -86,7 +86,7 @@ mod tests {
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
batch: u16,
|
||||
) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality,
|
||||
aspect_ratio,
|
||||
image_batch_count: Some(batch),
|
||||
@@ -105,7 +105,7 @@ mod tests {
|
||||
let tokens: Vec<MediaFileToken> = (0..num_input_images)
|
||||
.map(|i| MediaFileToken::new_from_str(&format!("mf_test{:028}", i)))
|
||||
.collect();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality,
|
||||
aspect_ratio,
|
||||
image_batch_count: Some(batch),
|
||||
|
||||
+2
-2
@@ -64,14 +64,14 @@ mod tests {
|
||||
use crate::api::common_quality::CommonQuality;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate(
|
||||
quality: Option<CommonQuality>,
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
batch: u16,
|
||||
) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage1p5,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::NanoBanana,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -46,10 +46,10 @@ mod tests {
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(resolution: Option<CommonResolution>, image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::NanoBanana2,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -40,10 +40,10 @@ mod tests {
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(resolution: Option<CommonResolution>, image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::NanoBananaPro,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -34,12 +34,12 @@ mod tests {
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let tokens = vec![MediaFileToken::new_from_str("test_token")];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::QwenEdit2511Angles,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Seedream4,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Seedream4p5,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Seedream5Lite,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
|
||||
+2
-2
@@ -38,10 +38,10 @@ mod tests {
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
|
||||
fn estimate_usd_cents(resolution: Option<CommonResolution>, image_batch_count: u16) -> u64 {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::NanoBananaPro,
|
||||
provider: Provider::Fal,
|
||||
prompt: None,
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ pub async fn execute_artcraft_flux_1_dev(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_flux_1_dev_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_1_dev() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -68,7 +68,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_1_dev_batch_four() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
quality: None,
|
||||
image_batch_count: Some(4),
|
||||
@@ -94,7 +94,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ pub async fn execute_artcraft_flux_1_schnell(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::test_helpers::{base_flux_1_schnell_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
@@ -44,7 +44,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_1_schnell() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -67,7 +67,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_1_schnell_batch_four() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
quality: None,
|
||||
image_batch_count: Some(4),
|
||||
@@ -93,7 +93,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ pub async fn execute_artcraft_flux_2_lora_angles(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_flux_2_lora_angles_image_request, get_artcraft_client};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
@@ -49,7 +49,7 @@ mod tests {
|
||||
async fn test_angle_edit_flux_2_lora() {
|
||||
let client = get_artcraft_client();
|
||||
let tokens = vec![MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8")];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::SquareHd),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ pub async fn execute_artcraft_flux_pro_1p1(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_flux_pro_1p1_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_pro_1p1() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -68,7 +68,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_pro_1p1_batch_four() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
quality: None,
|
||||
image_batch_count: Some(4),
|
||||
@@ -94,7 +94,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ pub async fn execute_artcraft_flux_pro_1p1_ultra(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_flux_pro_1p1_ultra_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_pro_1p1_ultra() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -68,7 +68,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_flux_pro_1p1_ultra_batch_four() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
quality: None,
|
||||
image_batch_count: Some(4),
|
||||
@@ -94,7 +94,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+5
-5
@@ -64,7 +64,7 @@ pub async fn execute_artcraft_gpt_image_1(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_gpt_image_1_image_request, get_artcraft_client};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
@@ -73,7 +73,7 @@ mod tests {
|
||||
// (no network I/O — we never call generate_image).
|
||||
#[test]
|
||||
fn build_text_to_image_plan_smoke() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_batch_count: Some(1),
|
||||
..base_gpt_image_1_image_request()
|
||||
@@ -88,7 +88,7 @@ mod tests {
|
||||
#[test]
|
||||
fn build_edit_image_plan_smoke() {
|
||||
let tokens = vec![MediaFileToken::new_from_str("mf_test00000000000000000000000000")];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_gpt_image_1_image_request()
|
||||
};
|
||||
@@ -103,7 +103,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_gpt_image_1() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
image_batch_count: Some(1),
|
||||
prompt: Some("a horse walking through a cyberpunk city at night".to_string()),
|
||||
@@ -128,7 +128,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a desert with cacti".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
|
||||
+5
-5
@@ -43,7 +43,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_gpt_image_1p5_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -53,7 +53,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_gpt_image_1p5() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
image_batch_count: Some(1),
|
||||
prompt: Some("a horse walking through a cyberpunk city at night".to_string()),
|
||||
@@ -80,7 +80,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a desert with cacti".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
@@ -106,7 +106,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
image_batch_count: Some(1),
|
||||
prompt: Some("a bear walking through a abandoned desert city at night".to_string()),
|
||||
@@ -139,7 +139,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- image-edit aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to an alien world".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(ar),
|
||||
|
||||
+6
-6
@@ -48,13 +48,13 @@ mod tests {
|
||||
use crate::api::common_quality::CommonQuality;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{get_artcraft_client, get_artcraft_client_for_env};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
fn base_gpt_image_2_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_gpt_image_2_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: crate::api::common_image_model::CommonImageModel::GptImage2,
|
||||
provider: crate::api::provider::Provider::Artcraft,
|
||||
prompt: Some("a t-rex walking through a cyberpunk city at night".to_string()),
|
||||
@@ -76,7 +76,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_gpt_image_2() {
|
||||
let client = get_artcraft_client_for_env(ApiHost::Localhost { port: 12345 });
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
image_batch_count: Some(1),
|
||||
..base_gpt_image_2_request()
|
||||
@@ -102,7 +102,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a desert with cacti".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens)),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
@@ -125,7 +125,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_gpt_image_2_high_quality() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
quality: Some(CommonQuality::High),
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+5
-5
@@ -38,7 +38,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_nano_banana_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -48,7 +48,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_nano_banana() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -76,7 +76,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a sunny beach".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
@@ -103,7 +103,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- image-edit aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a sunny beach".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(ar),
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ pub async fn execute_artcraft_nano_banana_2(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_nano_banana_2_image_request, get_artcraft_client};
|
||||
|
||||
@@ -46,7 +46,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_nano_banana_2() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution: Some(CommonResolution::OneK),
|
||||
quality: None,
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_image_request, get_artcraft_client};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
@@ -48,7 +48,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_nano_banana_pro() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution: Some(CommonResolution::OneK),
|
||||
quality: None,
|
||||
@@ -72,7 +72,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_nano_banana_pro_batch_four() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
resolution: Some(CommonResolution::OneK),
|
||||
quality: None,
|
||||
@@ -103,7 +103,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_2220d5we3masng5hvzg5zz68ywbdqd"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Add the man in the first image into the fantasy scene in the second image. Keep his hoodie and attire, but match the vibe of the fantasy scene.".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto), // edit mode: preserve source dimensions
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ pub async fn execute_artcraft_qwen_edit_2511_angles(
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_qwen_edit_2511_angles_image_request, get_artcraft_client};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
@@ -50,7 +50,7 @@ mod tests {
|
||||
async fn test_angle_edit_qwen_edit_2511() {
|
||||
let client = get_artcraft_client();
|
||||
let tokens = vec![MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8")];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::SquareHd),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+5
-5
@@ -39,7 +39,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_seedream_4_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -49,7 +49,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_seedream_4() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -77,7 +77,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a sunny beach".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
@@ -104,7 +104,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -138,7 +138,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- image-edit aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a sunny beach".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(ar),
|
||||
|
||||
+5
-5
@@ -39,7 +39,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_seedream_4p5_image_request, get_artcraft_client};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -49,7 +49,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_seedream_4p5() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -77,7 +77,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a spooky haunted house".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto2k),
|
||||
@@ -104,7 +104,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- text-to-image aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
@@ -138,7 +138,7 @@ mod tests {
|
||||
|
||||
for ar in CommonAspectRatio::iter() {
|
||||
println!("--- image-edit aspect ratio: {:?} ---", ar);
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Change the background to a spooky haunted house".to_string()),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(image_tokens.clone())),
|
||||
aspect_ratio: Some(ar),
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ pub async fn execute_artcraft_seedream_5_lite(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_seedream_5_lite_image_request, get_artcraft_client};
|
||||
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real API request and incurs cost
|
||||
async fn test_text_to_image_seedream_5_lite() {
|
||||
let client = get_artcraft_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
quality: None,
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+25
-11
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -6,44 +9,55 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
};
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_flux_1_dev::PlanFalFlux1Dev;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_flux_1_dev_edit_image_webhook::{
|
||||
enqueue_flux_1_dev_edit_image_webhook, Flux1DevEditImageArgs,
|
||||
enqueue_flux_1_dev_edit_image_webhook, Flux1DevEditImageArgs, Flux1DevEditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_1_dev_text_to_image_webhook::{
|
||||
enqueue_flux_1_dev_text_to_image_webhook, Flux1DevArgs,
|
||||
enqueue_flux_1_dev_text_to_image_webhook, Flux1DevArgs, Flux1DevRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_flux_1_dev(
|
||||
plan: &PlanFalFlux1Dev,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if let Some(image_url) = &plan.maybe_image_url {
|
||||
let (webhook_response, outbound_request) = if let Some(image_url) = &plan.maybe_image_url {
|
||||
// Image-to-image mode
|
||||
let args = Flux1DevEditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = Flux1DevEditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_url: image_url.clone(),
|
||||
num_images: plan.num_images.to_edit(),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Flux1DevEditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_flux_1_dev_edit_image_webhook(args)
|
||||
let resp = enqueue_flux_1_dev_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
// Text-to-image mode
|
||||
let args = Flux1DevArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = Flux1DevRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
aspect_ratio: plan.aspect_ratio,
|
||||
num_images: plan.num_images.to_t2i(),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Flux1DevArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_flux_1_dev_text_to_image_webhook(args)
|
||||
let resp = enqueue_flux_1_dev_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+24
-10
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -6,44 +9,55 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
};
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_flux_1_schnell::PlanFalFlux1Schnell;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_flux_1_schnell_edit_image_webhook::{
|
||||
enqueue_flux_1_schnell_edit_image_webhook, Flux1SchnellEditImageArgs,
|
||||
enqueue_flux_1_schnell_edit_image_webhook, Flux1SchnellEditImageArgs, Flux1SchnellEditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_1_schnell_text_to_image_webhook::{
|
||||
enqueue_flux_1_schnell_text_to_image_webhook, Flux1SchnellArgs,
|
||||
enqueue_flux_1_schnell_text_to_image_webhook, Flux1SchnellArgs, Flux1SchnellRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_flux_1_schnell(
|
||||
plan: &PlanFalFlux1Schnell,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if let Some(image_url) = &plan.maybe_image_url {
|
||||
let (webhook_response, outbound_request) = if let Some(image_url) = &plan.maybe_image_url {
|
||||
// Image-to-image (redux) mode
|
||||
let args = Flux1SchnellEditImageArgs {
|
||||
let request = Flux1SchnellEditImageRequest {
|
||||
image_url: image_url.clone(),
|
||||
num_images: plan.num_images.to_edit(),
|
||||
image_size: plan.edit_image_size,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Flux1SchnellEditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_flux_1_schnell_edit_image_webhook(args)
|
||||
let resp = enqueue_flux_1_schnell_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
// Text-to-image mode
|
||||
let args = Flux1SchnellArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = Flux1SchnellRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
aspect_ratio: plan.t2i_aspect_ratio,
|
||||
num_images: plan.num_images.to_t2i(),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Flux1SchnellArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_flux_1_schnell_text_to_image_webhook(args)
|
||||
let resp = enqueue_flux_1_schnell_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+11
-3
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -6,17 +9,21 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
};
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_flux_pro_1p1::PlanFalFluxPro11;
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_pro_11_text_to_image_webhook::{
|
||||
enqueue_flux_pro_11_text_to_image_webhook, FluxPro11Args,
|
||||
enqueue_flux_pro_11_text_to_image_webhook, FluxPro11Args, FluxPro11Request,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_flux_pro_1p1(
|
||||
plan: &PlanFalFluxPro11,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let args = FluxPro11Args {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = FluxPro11Request {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
aspect_ratio: plan.aspect_ratio,
|
||||
num_images: plan.num_images.to_fal(),
|
||||
};
|
||||
let outbound_request: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = FluxPro11Args {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
@@ -28,5 +35,6 @@ pub async fn execute_fal_flux_pro_1p1(
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+11
-3
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -6,17 +9,21 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
};
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_flux_pro_1p1_ultra::PlanFalFluxPro11Ultra;
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_pro_11_ultra_text_to_image_webhook::{
|
||||
enqueue_flux_pro_11_ultra_text_to_image_webhook, FluxPro11UltraArgs,
|
||||
enqueue_flux_pro_11_ultra_text_to_image_webhook, FluxPro11UltraArgs, FluxPro11UltraRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_flux_pro_1p1_ultra(
|
||||
plan: &PlanFalFluxPro11Ultra,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let args = FluxPro11UltraArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = FluxPro11UltraRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
aspect_ratio: plan.aspect_ratio,
|
||||
num_images: plan.num_images.to_fal(),
|
||||
};
|
||||
let outbound_request: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = FluxPro11UltraArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
@@ -28,5 +35,6 @@ pub async fn execute_fal_flux_pro_1p1_ultra(
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+32
-16
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,32 +10,39 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_gpt_image_1::PlanFalGptImage1;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_1_edit_image_webhook::{
|
||||
enqueue_gpt_image_1_edit_image_webhook, EnqueueGptImage1EditImageArgs,
|
||||
EnqueueGptImage1EditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_gpt_image_1_text_to_image_webhook::{
|
||||
enqueue_gpt_image_1_text_to_image_webhook, EnqueueGptImage1TextToImageArgs,
|
||||
EnqueueGptImage1TextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_gpt_image_1(
|
||||
plan: &PlanFalGptImage1,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueGptImage1TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueGptImage1TextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: plan.num_images.to_t2i(),
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
quality: Some(plan.quality.to_t2i()),
|
||||
background: None,
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage1TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_1_text_to_image_webhook(args)
|
||||
let resp = enqueue_gpt_image_1_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueGptImage1EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueGptImage1EditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: plan.num_images.to_edit(),
|
||||
mask_image_url: None,
|
||||
@@ -41,17 +51,23 @@ pub async fn execute_fal_gpt_image_1(
|
||||
input_fidelity: None,
|
||||
background: None,
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage1EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_1_edit_image_webhook(args)
|
||||
let resp = enqueue_gpt_image_1_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -63,12 +79,12 @@ mod tests {
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::get_fal_client;
|
||||
|
||||
fn base_fal_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_fal_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage1,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
@@ -89,7 +105,7 @@ mod tests {
|
||||
// Build-only smoke test (no network I/O).
|
||||
#[test]
|
||||
fn build_text_to_image_plan_smoke() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_batch_count: Some(1),
|
||||
..base_fal_request()
|
||||
@@ -105,7 +121,7 @@ mod tests {
|
||||
#[test]
|
||||
fn build_edit_image_plan_smoke() {
|
||||
let urls = vec!["https://example.com/img.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -120,7 +136,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real fal API request and incurs cost
|
||||
async fn test_text_to_image_gpt_image_1_fal() {
|
||||
let client = get_fal_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
image_batch_count: Some(1),
|
||||
prompt: Some("a horse walking through a cyberpunk city at night".to_string()),
|
||||
@@ -142,7 +158,7 @@ mod tests {
|
||||
let urls = vec![
|
||||
TREX_SKELETON_IMAGE_URL.to_string(),
|
||||
];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_batch_count: Some(1),
|
||||
|
||||
+25
-9
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,32 +10,39 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_gpt_image_1p5::PlanFalGptImage1p5;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_1p5_edit_image_webhook::{
|
||||
enqueue_gpt_image_1p5_image_edit_webhook, EnqueueGptImage1p5EditImageArgs,
|
||||
EnqueueGptImage1p5EditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_gpt_image_1p5_text_to_image_webhook::{
|
||||
enqueue_gpt_image_1p5_text_to_image_webhook, EnqueueGptImage1p5TextToImageArgs,
|
||||
EnqueueGptImage1p5TextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_gpt_image_1p5(
|
||||
plan: &PlanFalGptImage1p5,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueGptImage1p5TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueGptImage1p5TextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: plan.num_images.to_t2i(),
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
background: None,
|
||||
quality: Some(plan.quality.to_t2i()),
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage1p5TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_1p5_text_to_image_webhook(args)
|
||||
let resp = enqueue_gpt_image_1p5_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueGptImage1p5EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueGptImage1p5EditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: plan.num_images.to_edit(),
|
||||
mask_image_url: None,
|
||||
@@ -41,16 +51,22 @@ pub async fn execute_fal_gpt_image_1p5(
|
||||
quality: Some(plan.quality.to_edit()),
|
||||
input_fidelity: None,
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage1p5EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_1p5_image_edit_webhook(args)
|
||||
let resp = enqueue_gpt_image_1p5_image_edit_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+32
-16
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,48 +10,61 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_gpt_image_2::PlanFalGptImage2;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_2_edit_image_webhook::{
|
||||
enqueue_gpt_image_2_edit_image_webhook, EnqueueGptImage2EditImageArgs,
|
||||
EnqueueGptImage2EditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_gpt_image_2_text_to_image_webhook::{
|
||||
enqueue_gpt_image_2_text_to_image_webhook, EnqueueGptImage2TextToImageArgs,
|
||||
EnqueueGptImage2TextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_gpt_image_2(
|
||||
plan: &PlanFalGptImage2,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueGptImage2TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueGptImage2TextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: plan.num_images.to_t2i(),
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
quality: Some(plan.quality.to_t2i()),
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage2TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_2_text_to_image_webhook(args)
|
||||
let resp = enqueue_gpt_image_2_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueGptImage2EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueGptImage2EditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: plan.num_images.to_edit(),
|
||||
mask_url: None,
|
||||
image_size: plan.image_size.map(|s| s.to_edit()),
|
||||
quality: Some(plan.quality.to_edit()),
|
||||
output_format: None,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueGptImage2EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gpt_image_2_edit_image_webhook(args)
|
||||
let resp = enqueue_gpt_image_2_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -60,7 +76,7 @@ mod tests {
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::get_fal_client;
|
||||
|
||||
@@ -71,7 +87,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn text_to_image_plan() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_batch_count: Some(1),
|
||||
..base_request()
|
||||
@@ -89,7 +105,7 @@ mod tests {
|
||||
JUNO_AT_LAKE_IMAGE_URL.to_string(),
|
||||
GHOST_IMAGE_URL.to_string(),
|
||||
];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("dog running from a scary ghost".to_string()),
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_request()
|
||||
@@ -111,7 +127,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real fal API request and incurs cost
|
||||
async fn text_to_image() {
|
||||
let client = get_fal_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
image_batch_count: Some(1),
|
||||
prompt: Some("a horse walking through a cyberpunk city at night".to_string()),
|
||||
@@ -131,7 +147,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real fal API request and incurs cost
|
||||
async fn edit_image() {
|
||||
let client = get_fal_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("dog running from a scary ghost".to_string()),
|
||||
image_inputs: Some(ImageListRef::Urls(vec![
|
||||
JUNO_AT_LAKE_IMAGE_URL.to_string(),
|
||||
@@ -154,8 +170,8 @@ mod tests {
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn base_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage2,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
|
||||
+25
-11
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -9,47 +12,58 @@ use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_ban
|
||||
};
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gemini_25_flash_edit_webhook::{
|
||||
enqueue_gemini_25_flash_edit_webhook, Gemini25FlashEditArgs,
|
||||
Gemini25FlashEditNumImages,
|
||||
Gemini25FlashEditNumImages, Gemini25FlashEditRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_gemini_25_flash_text_to_image_webhook::{
|
||||
enqueue_gemini_25_flash_text_to_image_webhook, Gemini25FlashTextToImageArgs,
|
||||
Gemini25FlashTextToImageNumImages,
|
||||
Gemini25FlashTextToImageNumImages, Gemini25FlashTextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_nano_banana(
|
||||
plan: &PlanFalNanoBanana,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
// Text-to-image mode
|
||||
let args = Gemini25FlashTextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = Gemini25FlashTextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: to_t2i_num_images(plan.num_images),
|
||||
aspect_ratio: plan.t2i_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Gemini25FlashTextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gemini_25_flash_text_to_image_webhook(args)
|
||||
let resp = enqueue_gemini_25_flash_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
// Image-edit mode
|
||||
let args = Gemini25FlashEditArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = Gemini25FlashEditRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: to_edit_num_images(plan.num_images),
|
||||
aspect_ratio: plan.edit_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = Gemini25FlashEditArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gemini_25_flash_edit_webhook(args)
|
||||
let resp = enqueue_gemini_25_flash_edit_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
+27
-11
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -9,49 +12,62 @@ use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_ban
|
||||
};
|
||||
use fal_client::requests::webhook::image::edit::enqueue_nano_banana_2_edit_image_webhook::{
|
||||
enqueue_nano_banana_2_edit_image_webhook, EnqueueNanoBanana2EditImageArgs,
|
||||
EnqueueNanoBanana2EditImageNumImages, EnqueueNanoBanana2EditImageResolution,
|
||||
EnqueueNanoBanana2EditImageNumImages, EnqueueNanoBanana2EditImageRequest,
|
||||
EnqueueNanoBanana2EditImageResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_nano_banana_2_text_to_image_webhook::{
|
||||
enqueue_nano_banana_2_text_to_image_webhook, EnqueueNanoBanana2TextToImageArgs,
|
||||
EnqueueNanoBanana2TextToImageNumImages, EnqueueNanoBanana2TextToImageResolution,
|
||||
EnqueueNanoBanana2TextToImageNumImages, EnqueueNanoBanana2TextToImageRequest,
|
||||
EnqueueNanoBanana2TextToImageResolution,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_nano_banana_2(
|
||||
plan: &PlanFalNanaBanana2,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
// Text-to-image mode
|
||||
let args = EnqueueNanoBanana2TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueNanoBanana2TextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: to_t2i_num_images(plan.num_images),
|
||||
resolution: plan.resolution.map(to_t2i_resolution),
|
||||
aspect_ratio: plan.t2i_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueNanoBanana2TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_nano_banana_2_text_to_image_webhook(args)
|
||||
let resp = enqueue_nano_banana_2_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
// Image-edit mode
|
||||
let args = EnqueueNanoBanana2EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueNanoBanana2EditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: to_edit_num_images(plan.num_images),
|
||||
resolution: plan.resolution.map(to_edit_resolution),
|
||||
aspect_ratio: plan.edit_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueNanoBanana2EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_nano_banana_2_edit_image_webhook(args)
|
||||
let resp = enqueue_nano_banana_2_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
+31
-15
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -9,48 +12,61 @@ use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_ban
|
||||
};
|
||||
use fal_client::requests::webhook::image::edit::enqueue_nano_banana_pro_edit_image_webhook::{
|
||||
enqueue_nano_banana_pro_image_edit_webhook, EnqueueNanoBananaProEditImageArgs,
|
||||
EnqueueNanoBananaProEditImageNumImages, EnqueueNanoBananaProEditImageResolution,
|
||||
EnqueueNanoBananaProEditImageNumImages, EnqueueNanoBananaProEditImageRequest,
|
||||
EnqueueNanoBananaProEditImageResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_nano_banana_pro_text_to_image_webhook::{
|
||||
enqueue_nano_banana_pro_text_to_image_webhook, EnqueueNanoBananaProTextToImageArgs,
|
||||
EnqueueNanoBananaProTextToImageNumImages, EnqueueNanoBananaProTextToImageResolution,
|
||||
EnqueueNanoBananaProTextToImageNumImages, EnqueueNanoBananaProTextToImageRequest,
|
||||
EnqueueNanoBananaProTextToImageResolution,
|
||||
};
|
||||
pub async fn execute_fal_nano_banana_pro(
|
||||
plan: &PlanFalNanaBananaPro,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
// Text-to-image mode
|
||||
let args = EnqueueNanoBananaProTextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueNanoBananaProTextToImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
num_images: to_t2i_num_images(plan.num_images),
|
||||
resolution: plan.resolution.map(to_t2i_resolution),
|
||||
aspect_ratio: plan.t2i_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueNanoBananaProTextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_nano_banana_pro_text_to_image_webhook(args)
|
||||
let resp = enqueue_nano_banana_pro_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
// Image-edit mode
|
||||
let args = EnqueueNanoBananaProEditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueNanoBananaProEditImageRequest {
|
||||
prompt: plan.prompt.as_deref().unwrap_or("").to_string(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: to_edit_num_images(plan.num_images),
|
||||
resolution: plan.resolution.map(to_edit_resolution),
|
||||
aspect_ratio: plan.edit_aspect_ratio,
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueNanoBananaProEditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_nano_banana_pro_image_edit_webhook(args)
|
||||
let resp = enqueue_nano_banana_pro_image_edit_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -93,7 +109,7 @@ mod tests {
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::test_helpers::{base_fal_image_request, get_fal_client};
|
||||
use test_data::web::image_urls::{GHOST_IMAGE_URL, TREX_SKELETON_IMAGE_URL};
|
||||
@@ -102,7 +118,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real Fal API request
|
||||
async fn test_text_to_image_fal_nano_banana_pro() {
|
||||
let client = get_fal_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution: Some(CommonResolution::TwoK),
|
||||
quality: None,
|
||||
@@ -127,7 +143,7 @@ mod tests {
|
||||
#[ignore] // manually run — fires a real Fal API request
|
||||
async fn test_text_to_image_fal_nano_banana_pro_batch_four() {
|
||||
let client = get_fal_client();
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
resolution: Some(CommonResolution::OneK),
|
||||
quality: None,
|
||||
@@ -158,7 +174,7 @@ mod tests {
|
||||
TREX_SKELETON_IMAGE_URL.to_string(),
|
||||
];
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
prompt: Some("Add the ghost from the first image hovering above the T-Rex skeleton in the second image, make it look spooky but friendly".to_string()),
|
||||
image_inputs: Some(ImageListRef::Urls(image_urls.clone())),
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto), // edit mode: preserve source dimensions
|
||||
|
||||
+25
-9
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,44 +10,57 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_seedream_4::PlanFalSeedream4;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v4_edit_image_webhook::{
|
||||
enqueue_bytedance_seedream_v4_edit_image_webhook, EnqueueBytedanceSeedreamV4EditImageArgs,
|
||||
EnqueueBytedanceSeedreamV4EditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_bytedance_seedream_v4_text_to_image_webhook::{
|
||||
enqueue_bytedance_seedream_v4_text_to_image_webhook, EnqueueBytedanceSeedreamV4TextToImageArgs,
|
||||
EnqueueBytedanceSeedreamV4TextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_seedream_4(
|
||||
plan: &PlanFalSeedream4,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueBytedanceSeedreamV4TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueBytedanceSeedreamV4TextToImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
num_images: Some(plan.num_images.to_t2i()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV4TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v4_text_to_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v4_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueBytedanceSeedreamV4EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueBytedanceSeedreamV4EditImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: Some(plan.num_images.to_edit()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_edit()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV4EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v4_edit_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v4_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+25
-9
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,44 +10,57 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_seedream_4p5::PlanFalSeedream4p5;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v4p5_edit_image_webhook::{
|
||||
enqueue_bytedance_seedream_v4p5_edit_image_webhook, EnqueueBytedanceSeedreamV4p5EditImageArgs,
|
||||
EnqueueBytedanceSeedreamV4p5EditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_bytedance_seedream_v4p5_text_to_image_webhook::{
|
||||
enqueue_bytedance_seedream_v4p5_text_to_image_webhook, EnqueueBytedanceSeedreamV4p5TextToImageArgs,
|
||||
EnqueueBytedanceSeedreamV4p5TextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_seedream_4p5(
|
||||
plan: &PlanFalSeedream4p5,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueBytedanceSeedreamV4p5TextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueBytedanceSeedreamV4p5TextToImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
num_images: Some(plan.num_images.to_t2i()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV4p5TextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v4p5_text_to_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v4p5_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueBytedanceSeedreamV4p5EditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueBytedanceSeedreamV4p5EditImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: Some(plan.num_images.to_edit()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_edit()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV4p5EditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v4p5_edit_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v4p5_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+25
-9
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
@@ -7,44 +10,57 @@ use crate::generate::generate_image::generate_image_response::{
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_seedream_5_lite::PlanFalSeedream5Lite;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v5_lite_edit_image_webhook::{
|
||||
enqueue_bytedance_seedream_v5_lite_edit_image_webhook, EnqueueBytedanceSeedreamV5LiteEditImageArgs,
|
||||
EnqueueBytedanceSeedreamV5LiteEditImageRequest,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_bytedance_seedream_v5_lite_text_to_image_webhook::{
|
||||
enqueue_bytedance_seedream_v5_lite_text_to_image_webhook, EnqueueBytedanceSeedreamV5LiteTextToImageArgs,
|
||||
EnqueueBytedanceSeedreamV5LiteTextToImageRequest,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_seedream_5_lite(
|
||||
plan: &PlanFalSeedream5Lite,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
let args = EnqueueBytedanceSeedreamV5LiteTextToImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let (webhook_response, outbound_request) = if plan.image_urls.is_empty() {
|
||||
let request = EnqueueBytedanceSeedreamV5LiteTextToImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
num_images: Some(plan.num_images.to_t2i()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_t2i()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV5LiteTextToImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v5_lite_text_to_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v5_lite_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
} else {
|
||||
let args = EnqueueBytedanceSeedreamV5LiteEditImageArgs {
|
||||
prompt: plan.prompt.as_deref().unwrap_or(""),
|
||||
let request = EnqueueBytedanceSeedreamV5LiteEditImageRequest {
|
||||
prompt: plan.prompt.clone().unwrap_or_default(),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: Some(plan.num_images.to_edit()),
|
||||
max_images: None,
|
||||
image_size: plan.image_size.map(|s| s.to_edit()),
|
||||
};
|
||||
let outbound: Arc<dyn Debug + Send + Sync> = Arc::new(request.clone());
|
||||
let args = EnqueueBytedanceSeedreamV5LiteEditImageArgs {
|
||||
request,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_bytedance_seedream_v5_lite_edit_image_webhook(args)
|
||||
let resp = enqueue_bytedance_seedream_v5_lite_edit_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
(resp, outbound)
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
maybe_outbound_request: Some(outbound_request),
|
||||
}))
|
||||
}
|
||||
|
||||
+34
-2
@@ -9,6 +9,11 @@ use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigati
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use crate::generate::generate_image_v2::image_generation_draft_or_request::ImageGenerationDraftOrRequest;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_dev::build::build_fal_flux_1_dev;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_schnell::build::build_fal_flux_1_schnell;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_2::build::build_fal_nano_banana_2;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_pro::build::build_fal_nano_banana_pro;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_flux_1_dev::plan_generate_image_artcraft_flux_1_dev;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_flux_1_schnell::plan_generate_image_artcraft_flux_1_schnell;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_flux_2_lora_angles::plan_generate_image_artcraft_flux_2_lora_angles;
|
||||
@@ -39,7 +44,7 @@ use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_ban
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana_pro::plan_generate_image_fal_nano_banana_pro;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenerateImageRequest {
|
||||
pub struct GenerateImageRequestBuilder {
|
||||
/// Which model to use.
|
||||
pub model: CommonImageModel,
|
||||
|
||||
@@ -88,7 +93,28 @@ pub struct GenerateImageRequest {
|
||||
pub idempotency_token: Option<String>,
|
||||
}
|
||||
|
||||
impl GenerateImageRequest {
|
||||
impl GenerateImageRequestBuilder {
|
||||
|
||||
pub fn use_new_builder(&self) -> bool {
|
||||
match (self.provider, self.model) {
|
||||
(Provider::Fal, CommonImageModel::Flux1Dev) => true,
|
||||
(Provider::Fal, CommonImageModel::Flux1Schnell) => true,
|
||||
(Provider::Fal, CommonImageModel::NanoBanana2) => true,
|
||||
(Provider::Fal, CommonImageModel::NanoBananaPro) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build2(self) -> Result<ImageGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
match (self.provider, self.model) {
|
||||
(Provider::Fal, CommonImageModel::Flux1Dev) => build_fal_flux_1_dev(self),
|
||||
(Provider::Fal, CommonImageModel::Flux1Schnell) => build_fal_flux_1_schnell(self),
|
||||
(Provider::Fal, CommonImageModel::NanoBanana2) => build_fal_nano_banana_2(self),
|
||||
(Provider::Fal, CommonImageModel::NanoBananaPro) => build_fal_nano_banana_pro(self),
|
||||
_ => self.unsupported_provider_and_model(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the image generation request, construct a plan, then yield a means to execute it.
|
||||
pub fn build(&self) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
match self.provider {
|
||||
@@ -149,6 +175,12 @@ impl GenerateImageRequest {
|
||||
))
|
||||
}
|
||||
|
||||
fn unsupported_provider_and_model(&self) -> Result<ImageGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(
|
||||
format!("Image generation for model `{:?}` is not supported for provider {:?} using the new API", self.model, self.provider)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_or_generate_idempotency_token(&self) -> String {
|
||||
self.idempotency_token.clone()
|
||||
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string())
|
||||
+8
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -9,6 +12,11 @@ pub struct ArtcraftImageResponsePayload {
|
||||
pub struct FalImageResponsePayload {
|
||||
pub request_id: Option<String>,
|
||||
pub gateway_request_id: Option<String>,
|
||||
|
||||
/// The outbound request that was sent to Fal.
|
||||
/// Stored as a trait object so any Request type can be captured.
|
||||
/// Use `format!("{:?}", ...)` or `format!("{:#?}", ...)` to print.
|
||||
pub maybe_outbound_request: Option<Arc<dyn Debug + Send + Sync>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pub mod cost;
|
||||
pub mod execute;
|
||||
pub mod generate_image_request;
|
||||
pub mod generate_image_request_builder;
|
||||
pub mod generate_image_response;
|
||||
pub mod image_generation_cost_estimate;
|
||||
pub mod image_generation_plan;
|
||||
|
||||
+15
-15
@@ -3,7 +3,7 @@ use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStra
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_1_dev_text_to_image::{
|
||||
GenerateFlux1DevTextToImageAspectRatio, GenerateFlux1DevTextToImageNumImages,
|
||||
@@ -18,7 +18,7 @@ pub struct PlanArtcraftFlux1Dev {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_flux_1_dev(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
// Flux 1 Dev is text-to-image only. Abort if image inputs are provided and
|
||||
// the caller has opted into strict mode.
|
||||
@@ -134,7 +134,7 @@ mod tests {
|
||||
use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::test_helpers::base_flux_1_dev_image_request;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_1_dev_text_to_image::{
|
||||
GenerateFlux1DevTextToImageAspectRatio as FlAr,
|
||||
@@ -146,7 +146,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_abort_returns_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::AbortGeneration),
|
||||
..base_flux_1_dev_image_request()
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_generate_anyway_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::GenerateAnyway),
|
||||
..base_flux_1_dev_image_request()
|
||||
@@ -172,7 +172,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_none_strategy_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: None,
|
||||
..base_flux_1_dev_image_request()
|
||||
@@ -184,7 +184,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_flux_1_dev_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_flux_1_dev_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Dev(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Dev") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -192,7 +192,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_auto_falls_back_to_square() {
|
||||
for ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_flux_1_dev_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_flux_1_dev_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Dev(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Dev") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(FlAr::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallNineByTwentyOne, FlAr::PortraitNineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_flux_1_dev_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_flux_1_dev_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Dev(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Dev") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -227,7 +227,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_flux_1_dev_image_request()
|
||||
@@ -245,7 +245,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_flux_1_dev_image_request()
|
||||
@@ -267,7 +267,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -284,7 +284,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, FlN::One), (2, FlN::Two), (3, FlN::Three), (4, FlN::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_flux_1_dev_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_flux_1_dev_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Dev(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Dev") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -295,7 +295,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
|
||||
+15
-15
@@ -3,7 +3,7 @@ use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStra
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_1_schnell_text_to_image::{
|
||||
GenerateFlux1SchnellTextToImageAspectRatio, GenerateFlux1SchnellTextToImageNumImages,
|
||||
@@ -18,7 +18,7 @@ pub struct PlanArtcraftFlux1Schnell {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_flux_1_schnell(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
// Flux 1 Schnell is text-to-image only. Abort if image inputs are provided and
|
||||
// the caller has opted into strict mode.
|
||||
@@ -134,7 +134,7 @@ mod tests {
|
||||
use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::test_helpers::base_flux_1_schnell_image_request;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_1_schnell_text_to_image::{
|
||||
GenerateFlux1SchnellTextToImageAspectRatio as FlAr,
|
||||
@@ -146,7 +146,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_abort_returns_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::AbortGeneration),
|
||||
..base_flux_1_schnell_image_request()
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_generate_anyway_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::GenerateAnyway),
|
||||
..base_flux_1_schnell_image_request()
|
||||
@@ -172,7 +172,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_none_strategy_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: None,
|
||||
..base_flux_1_schnell_image_request()
|
||||
@@ -184,7 +184,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_flux_1_schnell_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_flux_1_schnell_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Schnell(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Schnell") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -192,7 +192,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_auto_falls_back_to_square() {
|
||||
for ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_flux_1_schnell_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_flux_1_schnell_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Schnell(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Schnell") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(FlAr::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallNineByTwentyOne, FlAr::PortraitNineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_flux_1_schnell_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_flux_1_schnell_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Schnell(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Schnell") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -227,7 +227,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_flux_1_schnell_image_request()
|
||||
@@ -244,7 +244,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_flux_1_schnell_image_request()
|
||||
@@ -263,7 +263,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -280,7 +280,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, FlN::One), (2, FlN::Two), (3, FlN::Three), (4, FlN::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_flux_1_schnell_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_flux_1_schnell_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFlux1Schnell(plan) = request.build().unwrap() else { panic!("expected ArtcraftFlux1Schnell") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -291,7 +291,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -309,7 +309,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
|
||||
+10
-10
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::angle::flux_2_lora_edit_image_angle::{
|
||||
Flux2LoraEditImageAngleImageSize,
|
||||
@@ -23,7 +23,7 @@ pub struct PlanArtcraftFlux2LoraAngles {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_flux_2_lora_angles(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -153,7 +153,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn requires_image_input() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: None,
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
};
|
||||
@@ -164,7 +164,7 @@ mod tests {
|
||||
#[test]
|
||||
fn rejects_urls() {
|
||||
let urls = vec!["https://example.com/img.png".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
};
|
||||
@@ -175,7 +175,7 @@ mod tests {
|
||||
#[test]
|
||||
fn accepts_single_media_token() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
};
|
||||
@@ -186,7 +186,7 @@ mod tests {
|
||||
#[test]
|
||||
fn rejects_multiple_media_tokens() {
|
||||
let tokens = vec![make_token(), make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
};
|
||||
@@ -197,7 +197,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: None,
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
@@ -209,7 +209,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square_maps_directly() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_flux_2_lora_angles_image_request()
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
let tokens = vec![make_token()];
|
||||
let cases = [(1, N::One), (2, N::Two), (3, N::Three), (4, N::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(count),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
@@ -240,7 +240,7 @@ mod tests {
|
||||
#[test]
|
||||
fn angle_fields_are_passed_through() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
horizontal_angle: Some(45.0),
|
||||
vertical_angle: Some(-30.0),
|
||||
zoom: Some(1.5),
|
||||
|
||||
+15
-15
@@ -3,7 +3,7 @@ use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStra
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_pro_11_text_to_image::{
|
||||
GenerateFluxPro11TextToImageAspectRatio, GenerateFluxPro11TextToImageNumImages,
|
||||
@@ -18,7 +18,7 @@ pub struct PlanArtcraftFluxPro11 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_flux_pro_1p1(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
// Flux Pro 1.1 is text-to-image only. Abort if image inputs are provided and
|
||||
// the caller has opted into strict mode.
|
||||
@@ -134,7 +134,7 @@ mod tests {
|
||||
use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::test_helpers::base_flux_pro_1p1_image_request;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_pro_11_text_to_image::{
|
||||
GenerateFluxPro11TextToImageAspectRatio as FlAr,
|
||||
@@ -146,7 +146,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_abort_returns_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::AbortGeneration),
|
||||
..base_flux_pro_1p1_image_request()
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_generate_anyway_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::GenerateAnyway),
|
||||
..base_flux_pro_1p1_image_request()
|
||||
@@ -172,7 +172,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_none_strategy_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: None,
|
||||
..base_flux_pro_1p1_image_request()
|
||||
@@ -184,7 +184,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_flux_pro_1p1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_flux_pro_1p1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -197,7 +197,7 @@ mod tests {
|
||||
CommonAspectRatio::Auto4k,
|
||||
CommonAspectRatio::SquareHd,
|
||||
] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_flux_pro_1p1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_flux_pro_1p1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(FlAr::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallNineByTwentyOne, FlAr::PortraitNineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_flux_pro_1p1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_flux_pro_1p1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -231,7 +231,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_flux_pro_1p1_image_request()
|
||||
@@ -248,7 +248,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_flux_pro_1p1_image_request()
|
||||
@@ -267,7 +267,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -284,7 +284,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, FlN::One), (2, FlN::Two), (3, FlN::Three), (4, FlN::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_flux_pro_1p1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_flux_pro_1p1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -295,7 +295,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
|
||||
+15
-15
@@ -3,7 +3,7 @@ use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStra
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_pro_11_ultra_text_to_image::{
|
||||
GenerateFluxPro11UltraTextToImageAspectRatio, GenerateFluxPro11UltraTextToImageNumImages,
|
||||
@@ -18,7 +18,7 @@ pub struct PlanArtcraftFluxPro11Ultra {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_flux_pro_1p1_ultra(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
// Flux Pro 1.1 Ultra is text-to-image only. Abort if image inputs are provided and
|
||||
// the caller has opted into strict mode.
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
use crate::client::generation_mode_mismatch_strategy::GenerationModeMismatchStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::test_helpers::base_flux_pro_1p1_ultra_image_request;
|
||||
use artcraft_api_defs::generate::image::text::generate_flux_pro_11_ultra_text_to_image::{
|
||||
GenerateFluxPro11UltraTextToImageAspectRatio as FlAr,
|
||||
@@ -149,7 +149,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_abort_returns_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::AbortGeneration),
|
||||
..base_flux_pro_1p1_ultra_image_request()
|
||||
@@ -164,7 +164,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_generate_anyway_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: Some(GenerationModeMismatchStrategy::GenerateAnyway),
|
||||
..base_flux_pro_1p1_ultra_image_request()
|
||||
@@ -175,7 +175,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_inputs_with_none_strategy_succeeds() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
generation_mode_mismatch_strategy: None,
|
||||
..base_flux_pro_1p1_ultra_image_request()
|
||||
@@ -187,7 +187,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11Ultra(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11Ultra") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -200,7 +200,7 @@ mod tests {
|
||||
CommonAspectRatio::Auto4k,
|
||||
CommonAspectRatio::SquareHd,
|
||||
] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11Ultra(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11Ultra") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(FlAr::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallNineByTwentyOne, FlAr::PortraitNineByTwentyOne),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11Ultra(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11Ultra") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -234,7 +234,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_flux_pro_1p1_ultra_image_request()
|
||||
@@ -251,7 +251,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_flux_pro_1p1_ultra_image_request()
|
||||
@@ -270,7 +270,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -287,7 +287,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, FlN::One), (2, FlN::Two), (3, FlN::Three), (4, FlN::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_flux_pro_1p1_ultra_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftFluxPro11Ultra(plan) = request.build().unwrap() else { panic!("expected ArtcraftFluxPro11Ultra") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -298,7 +298,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -316,7 +316,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
|
||||
+16
-16
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::edit::gpt_image_1_edit_image::{
|
||||
GptImage1EditImageImageQuality, GptImage1EditImageImageSize, GptImage1EditImageNumImages,
|
||||
@@ -60,7 +60,7 @@ pub struct PlanArtcraftGptImage1 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_gpt_image_1(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -256,7 +256,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -266,7 +266,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto_variants_yield_none() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(auto_ar), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(auto_ar), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -277,7 +277,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square_variants() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -296,7 +296,7 @@ mod tests {
|
||||
CommonAspectRatio::Wide,
|
||||
];
|
||||
for ar in wide_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -315,7 +315,7 @@ mod tests {
|
||||
CommonAspectRatio::Tall,
|
||||
];
|
||||
for ar in tall_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -343,7 +343,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_gpt_image_1_image_request()
|
||||
@@ -358,7 +358,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_default_is_one() {
|
||||
let request = GenerateImageRequest { image_batch_count: None, ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: None, ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
(4, ArtcraftGptImage1NumImages::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -387,7 +387,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_gpt_image_1_image_request()
|
||||
@@ -405,7 +405,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(9),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_gpt_image_1_image_request()
|
||||
@@ -424,7 +424,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
@@ -434,7 +434,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_gpt_image_1_image_request()
|
||||
};
|
||||
@@ -450,7 +450,7 @@ mod tests {
|
||||
// cost estimation against Artcraft. URLs are accepted (and dropped) since
|
||||
// cost only depends on quality + size + num_images.
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_gpt_image_1_image_request()
|
||||
};
|
||||
@@ -474,7 +474,7 @@ mod tests {
|
||||
#[test]
|
||||
fn idempotency_token_passthrough() {
|
||||
let token = "11111111-1111-1111-1111-111111111111";
|
||||
let request = GenerateImageRequest { idempotency_token: Some(token.to_string()), ..base_gpt_image_1_image_request() };
|
||||
let request = GenerateImageRequestBuilder { idempotency_token: Some(token.to_string()), ..base_gpt_image_1_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1(plan) = request.build().unwrap() else {
|
||||
panic!("expected ArtcraftGptImage1")
|
||||
};
|
||||
|
||||
+14
-14
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::gpt_image_1p5_multi_function_image_gen::{
|
||||
GptImage1p5MultiFunctionImageGenNumImages, GptImage1p5MultiFunctionImageGenQuality,
|
||||
@@ -25,7 +25,7 @@ pub struct PlanArtcraftGptImage1p5 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_gpt_image_1p5(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -148,7 +148,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(plan.image_size.is_none());
|
||||
}
|
||||
@@ -156,7 +156,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto_variants_yield_none() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(auto_ar), ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(auto_ar), ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(plan.image_size.is_none(), "expected None for {:?}", auto_ar);
|
||||
}
|
||||
@@ -165,7 +165,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square_variants() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(matches!(plan.image_size, Some(GS::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ mod tests {
|
||||
CommonAspectRatio::Wide,
|
||||
];
|
||||
for ar in wide_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(matches!(plan.image_size, Some(GS::Wide)), "expected Wide for {:?}", ar);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
CommonAspectRatio::Tall,
|
||||
];
|
||||
for ar in tall_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(matches!(plan.image_size, Some(GS::Tall)), "expected Tall for {:?}", ar);
|
||||
}
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_gpt_image_1p5_image_request()
|
||||
@@ -245,7 +245,7 @@ mod tests {
|
||||
(4, GN::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -256,7 +256,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_gpt_image_1p5_image_request()
|
||||
@@ -274,7 +274,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_gpt_image_1p5_image_request()
|
||||
@@ -292,7 +292,7 @@ mod tests {
|
||||
#[test]
|
||||
fn url_image_inputs_are_accepted_for_cost_path() {
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_gpt_image_1p5_image_request()
|
||||
};
|
||||
@@ -304,7 +304,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_gpt_image_1p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_gpt_image_1p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftGptImage1p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftGptImage1p5") };
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
@@ -312,7 +312,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_gpt_image_1p5_image_request()
|
||||
};
|
||||
|
||||
+24
-24
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum;
|
||||
use enums::common::generation::common_quality::CommonQuality as CommonQualityEnum;
|
||||
@@ -49,7 +49,7 @@ pub struct PlanArtcraftGptImage2 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_gpt_image_2(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_yields_none() {
|
||||
let plan = build_plan(&GenerateImageRequest { image_inputs: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_inputs: None, ..base_request() });
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ mod tests {
|
||||
MediaFileToken::new_from_str("mf_test_a"),
|
||||
MediaFileToken::new_from_str("mf_test_b"),
|
||||
];
|
||||
let plan = build_plan(&GenerateImageRequest {
|
||||
let plan = build_plan(&GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_request()
|
||||
});
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
#[test]
|
||||
fn url_inputs_are_accepted_for_cost_path() {
|
||||
let urls = vec!["https://example.com/a.jpg".to_string()];
|
||||
let plan = build_plan(&GenerateImageRequest {
|
||||
let plan = build_plan(&GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls)),
|
||||
..base_request()
|
||||
});
|
||||
@@ -241,19 +241,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn low() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::Low), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::Low), ..base_request() });
|
||||
assert!(matches!(plan.quality, ArtcraftGptImage2Quality::Low));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn medium() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::Medium), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::Medium), ..base_request() });
|
||||
assert!(matches!(plan.quality, ArtcraftGptImage2Quality::Medium));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::High), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::High), ..base_request() });
|
||||
assert!(matches!(plan.quality, ArtcraftGptImage2Quality::High));
|
||||
}
|
||||
}
|
||||
@@ -265,34 +265,34 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn none_yields_auto() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: None, ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Auto)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_variants_yield_auto() {
|
||||
for ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Auto)), "expected Auto for {:?}", ar);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(CommonAspectRatio::Square), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(CommonAspectRatio::Square), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Square)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_hd() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(CommonAspectRatio::SquareHd), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(CommonAspectRatio::SquareHd), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::SquareHd)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn landscape_4x3_variants() {
|
||||
for ar in [CommonAspectRatio::WideFourByThree, CommonAspectRatio::WideFiveByFour] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Landscape4x3)), "expected Landscape4x3 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -305,7 +305,7 @@ mod tests {
|
||||
CommonAspectRatio::WideTwentyOneByNine,
|
||||
CommonAspectRatio::Wide,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Landscape16x9)), "expected Landscape16x9 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
#[test]
|
||||
fn portrait_4x3_variants() {
|
||||
for ar in [CommonAspectRatio::TallThreeByFour, CommonAspectRatio::TallFourByFive] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Portrait4x3)), "expected Portrait4x3 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -326,7 +326,7 @@ mod tests {
|
||||
CommonAspectRatio::TallNineByTwentyOne,
|
||||
CommonAspectRatio::Tall,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(ArtcraftGptImage2ImageSize::Portrait16x9)), "expected Portrait16x9 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -339,14 +339,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn default_is_one() {
|
||||
let plan = build_plan(&GenerateImageRequest { image_batch_count: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_batch_count: None, ..base_request() });
|
||||
assert!(matches!(plan.num_images, ArtcraftGptImage2NumImages::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_mapping() {
|
||||
for (count, expected) in [(1, 1), (2, 2), (3, 3), (4, 4)] {
|
||||
let plan = build_plan(&GenerateImageRequest { image_batch_count: Some(count), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_request() });
|
||||
assert_eq!(plan.num_images.as_u64(), expected);
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let result = plan_generate_image_artcraft_gpt_image_2(&GenerateImageRequest {
|
||||
let result = plan_generate_image_artcraft_gpt_image_2(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_request()
|
||||
@@ -369,7 +369,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn out_of_range_error_out() {
|
||||
let result = plan_generate_image_artcraft_gpt_image_2(&GenerateImageRequest {
|
||||
let result = plan_generate_image_artcraft_gpt_image_2(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_request()
|
||||
@@ -383,7 +383,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest {
|
||||
let plan = build_plan(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(9),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_request()
|
||||
@@ -405,8 +405,8 @@ mod tests {
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn base_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage2,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
@@ -424,7 +424,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_plan(request: &GenerateImageRequest) -> PlanArtcraftGptImage2 {
|
||||
fn build_plan(request: &GenerateImageRequestBuilder) -> PlanArtcraftGptImage2 {
|
||||
let ImageGenerationPlan::ArtcraftGptImage2(plan) =
|
||||
plan_generate_image_artcraft_gpt_image_2(request).expect("plan should succeed")
|
||||
else {
|
||||
|
||||
+17
-17
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::nano_banana_multi_function_image_gen::{
|
||||
NanoBananaMultiFunctionImageGenAspectRatio, NanoBananaMultiFunctionImageGenNumImages,
|
||||
@@ -21,7 +21,7 @@ pub struct PlanArtcraftNanaBanana {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_nano_banana(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -163,7 +163,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -171,7 +171,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_direct_square() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(NbAr::OneByOne)), "expected OneByOne for {:?}", ar);
|
||||
}
|
||||
@@ -188,7 +188,7 @@ mod tests {
|
||||
(CommonAspectRatio::WideTwentyOneByNine, NbAr::TwentyOneByNine),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -207,7 +207,7 @@ mod tests {
|
||||
(CommonAspectRatio::Tall, NbAr::NineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
fn aspect_ratio_auto_in_edit_mode_yields_auto() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_nano_banana_image_request()
|
||||
@@ -236,7 +236,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_auto_in_text_to_image_mode_falls_back_to_square() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: None,
|
||||
..base_nano_banana_image_request()
|
||||
@@ -252,7 +252,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
// TallNineByTwentyOne has no direct equivalent
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_nano_banana_image_request()
|
||||
@@ -271,7 +271,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_nano_banana_image_request()
|
||||
@@ -293,7 +293,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -316,7 +316,7 @@ mod tests {
|
||||
(4, NbN::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -327,7 +327,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -346,7 +346,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -368,7 +368,7 @@ mod tests {
|
||||
// cost estimation against Artcraft. URLs are accepted (and dropped) since
|
||||
// cost only depends on num_images + is_edit_mode.
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_nano_banana_image_request()
|
||||
};
|
||||
@@ -382,7 +382,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_nano_banana_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_nano_banana_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana") };
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
@@ -390,7 +390,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_nano_banana_image_request()
|
||||
};
|
||||
|
||||
+10
-10
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::nano_banana_2_multi_function_image_gen::{
|
||||
NanaBanana2MultiFunctionImageGenAspectRatio, NanaBanana2MultiFunctionImageGenImageResolution,
|
||||
@@ -24,7 +24,7 @@ pub struct PlanArtcraftNanaBanana2 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_nano_banana_2(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -191,7 +191,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_nano_banana_2_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_nano_banana_2_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana2(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana2") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_direct_square() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_nano_banana_2_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_nano_banana_2_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana2(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana2") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(Nb2Ar::OneByOne)), "expected OneByOne for {:?}", ar);
|
||||
}
|
||||
@@ -209,7 +209,7 @@ mod tests {
|
||||
fn aspect_ratio_auto_in_edit_mode_yields_auto() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_nano_banana_2_image_request()
|
||||
@@ -225,7 +225,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_auto_in_text_to_image_falls_back_to_square() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: None,
|
||||
..base_nano_banana_2_image_request()
|
||||
@@ -242,7 +242,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_none_is_none() {
|
||||
let request = GenerateImageRequest { resolution: None, ..base_nano_banana_2_image_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: None, ..base_nano_banana_2_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana2(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana2") };
|
||||
assert!(plan.resolution.is_none());
|
||||
}
|
||||
@@ -255,7 +255,7 @@ mod tests {
|
||||
(CommonResolution::FourK, Nb2Res::FourK),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { resolution: Some(common), ..base_nano_banana_2_image_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: Some(common), ..base_nano_banana_2_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana2(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana2") };
|
||||
assert!(
|
||||
matches!(plan.resolution, Some(r) if std::mem::discriminant(&r) == std::mem::discriminant(&expected)),
|
||||
@@ -266,7 +266,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_three_k_falls_back_to_two_k() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
resolution: Some(CommonResolution::ThreeK),
|
||||
..base_nano_banana_2_image_request()
|
||||
};
|
||||
@@ -285,7 +285,7 @@ mod tests {
|
||||
(4, Nb2N::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_nano_banana_2_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_nano_banana_2_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBanana2(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBanana2") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
|
||||
+20
-20
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::nano_banana_pro_multi_function_image_gen::{
|
||||
NanoBananaProMultiFunctionImageGenAspectRatio, NanoBananaProMultiFunctionImageGenImageResolution,
|
||||
@@ -24,7 +24,7 @@ pub struct PlanArtcraftNanaBananaPro {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_nano_banana_pro(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -189,7 +189,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(plan.aspect_ratio.is_none());
|
||||
}
|
||||
@@ -197,7 +197,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_direct_square() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(matches!(plan.aspect_ratio, Some(NbpAr::OneByOne)), "expected OneByOne for {:?}", ar);
|
||||
}
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
(CommonAspectRatio::WideTwentyOneByNine, NbpAr::TwentyOneByNine),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -233,7 +233,7 @@ mod tests {
|
||||
(CommonAspectRatio::Tall, NbpAr::NineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(
|
||||
matches!(plan.aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -247,7 +247,7 @@ mod tests {
|
||||
// Auto is only valid for edit mode (image_inputs present)
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_image_request()
|
||||
@@ -263,7 +263,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_auto_in_text_to_image_mode_falls_back_to_square() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: None,
|
||||
..base_image_request()
|
||||
@@ -279,7 +279,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aspect_ratio_unsupported_error_out() {
|
||||
// TallNineByTwentyOne has no direct equivalent
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_image_request()
|
||||
@@ -298,7 +298,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_image_request()
|
||||
@@ -315,7 +315,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_none_is_none() {
|
||||
let request = GenerateImageRequest { resolution: None, ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: None, ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(plan.resolution.is_none());
|
||||
}
|
||||
@@ -328,7 +328,7 @@ mod tests {
|
||||
(CommonResolution::FourK, NbpRes::FourK),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { resolution: Some(common), ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: Some(common), ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(
|
||||
matches!(plan.resolution, Some(r) if std::mem::discriminant(&r) == std::mem::discriminant(&expected)),
|
||||
@@ -339,7 +339,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_three_k_falls_back_to_two_k() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
resolution: Some(CommonResolution::ThreeK),
|
||||
..base_image_request()
|
||||
};
|
||||
@@ -356,7 +356,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -379,7 +379,7 @@ mod tests {
|
||||
(4, NbpN::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -390,7 +390,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -409,7 +409,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -431,7 +431,7 @@ mod tests {
|
||||
// cost estimation against Artcraft. URLs are accepted (and dropped) since
|
||||
// cost only depends on num_images + resolution + is_edit_mode.
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_image_request()
|
||||
};
|
||||
@@ -443,7 +443,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftNanaBananaPro(plan) = request.build().unwrap() else { panic!("expected ArtcraftNanaBananaPro") };
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
@@ -451,7 +451,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_image_request()
|
||||
};
|
||||
|
||||
+10
-10
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::angle::qwen_edit_2511_edit_image_angle::{
|
||||
QwenEdit2511EditImageAngleImageSize,
|
||||
@@ -24,7 +24,7 @@ pub struct PlanArtcraftQwenEdit2511Angles {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_qwen_edit_2511_angles(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -155,7 +155,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn requires_image_input() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: None,
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
};
|
||||
@@ -166,7 +166,7 @@ mod tests {
|
||||
#[test]
|
||||
fn rejects_urls() {
|
||||
let urls = vec!["https://example.com/img.png".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
};
|
||||
@@ -177,7 +177,7 @@ mod tests {
|
||||
#[test]
|
||||
fn accepts_single_media_token() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
};
|
||||
@@ -188,7 +188,7 @@ mod tests {
|
||||
#[test]
|
||||
fn rejects_multiple_media_tokens() {
|
||||
let tokens = vec![make_token(), make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
};
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: None,
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
@@ -211,7 +211,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square_maps_directly() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_qwen_edit_2511_angles_image_request()
|
||||
@@ -225,7 +225,7 @@ mod tests {
|
||||
let tokens = vec![make_token()];
|
||||
let cases = [(1, N::One), (2, N::Two), (3, N::Three), (4, N::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(count),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
@@ -242,7 +242,7 @@ mod tests {
|
||||
#[test]
|
||||
fn angle_fields_are_passed_through() {
|
||||
let tokens = vec![make_token()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
horizontal_angle: Some(45.0),
|
||||
vertical_angle: Some(-30.0),
|
||||
zoom: Some(1.5),
|
||||
|
||||
+19
-19
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_v4_multi_function_image_gen::{
|
||||
BytedanceSeedreamV4MultiFunctionImageGenImageSize,
|
||||
@@ -22,7 +22,7 @@ pub struct PlanArtcraftSeedream4 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_seedream_4(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -159,7 +159,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(plan.image_size.is_none());
|
||||
}
|
||||
@@ -167,7 +167,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
let expected = match ar {
|
||||
CommonAspectRatio::Square => S::Square,
|
||||
@@ -189,7 +189,7 @@ mod tests {
|
||||
(CommonAspectRatio::WideFourByThree, S::LandscapeFourThree),
|
||||
];
|
||||
for (ar, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -206,7 +206,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallThreeByFour, S::PortraitFourThree),
|
||||
];
|
||||
for (ar, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -218,7 +218,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto_in_edit_mode_yields_auto() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_seedream_4_image_request()
|
||||
@@ -229,7 +229,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_auto_in_text_to_image_yields_square() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: None,
|
||||
..base_seedream_4_image_request()
|
||||
@@ -241,7 +241,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto2k_and_auto4k() {
|
||||
for (ar, expected) in [(CommonAspectRatio::Auto2k, S::Auto2k), (CommonAspectRatio::Auto4k, S::Auto4k)] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -253,7 +253,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_unsupported_error_out() {
|
||||
for ar in [CommonAspectRatio::WideFiveByFour, CommonAspectRatio::TallFourByFive] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_seedream_4_image_request()
|
||||
@@ -268,7 +268,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_unsupported_nearest_match() {
|
||||
for strategy in [RequestMismatchMitigationStrategy::PayMoreUpgrade, RequestMismatchMitigationStrategy::PayLessDowngrade] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideFiveByFour),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_seedream_4_image_request()
|
||||
@@ -276,7 +276,7 @@ mod tests {
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(matches!(plan.image_size, Some(S::LandscapeSixteenNine)), "expected LandscapeSixteenNine with {:?}", strategy);
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_seedream_4_image_request()
|
||||
@@ -295,7 +295,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -312,7 +312,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, N::One), (2, N::Two), (3, N::Three), (4, N::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -323,7 +323,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -338,7 +338,7 @@ mod tests {
|
||||
#[test]
|
||||
fn num_images_out_of_range_clamps_to_four() {
|
||||
for strategy in [RequestMismatchMitigationStrategy::PayMoreUpgrade, RequestMismatchMitigationStrategy::PayLessDowngrade] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -354,7 +354,7 @@ mod tests {
|
||||
#[test]
|
||||
fn url_image_inputs_are_accepted_for_cost_path() {
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_seedream_4_image_request()
|
||||
};
|
||||
@@ -366,7 +366,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_seedream_4_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_seedream_4_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4") };
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_seedream_4_image_request()
|
||||
};
|
||||
|
||||
+19
-19
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_v4p5_multi_function_image_gen::{
|
||||
BytedanceSeedreamV4p5MultiFunctionImageGenImageSize,
|
||||
@@ -22,7 +22,7 @@ pub struct PlanArtcraftSeedream4p5 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_seedream_4p5(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -159,7 +159,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(plan.image_size.is_none());
|
||||
}
|
||||
@@ -167,7 +167,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
let expected = match ar {
|
||||
CommonAspectRatio::Square => S::Square,
|
||||
@@ -189,7 +189,7 @@ mod tests {
|
||||
(CommonAspectRatio::WideFourByThree, S::LandscapeFourThree),
|
||||
];
|
||||
for (ar, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -206,7 +206,7 @@ mod tests {
|
||||
(CommonAspectRatio::TallThreeByFour, S::PortraitFourThree),
|
||||
];
|
||||
for (ar, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -219,7 +219,7 @@ mod tests {
|
||||
fn image_size_auto_in_edit_mode_yields_auto2k() {
|
||||
// V4.5 has no bare Auto; falls back to Auto2k in edit mode
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_seedream_4p5_image_request()
|
||||
@@ -230,7 +230,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_auto_in_text_to_image_yields_square() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: None,
|
||||
..base_seedream_4p5_image_request()
|
||||
@@ -242,7 +242,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto2k_and_auto4k() {
|
||||
for (ar, expected) in [(CommonAspectRatio::Auto2k, S::Auto2k), (CommonAspectRatio::Auto4k, S::Auto4k)] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(
|
||||
matches!(plan.image_size, Some(s) if std::mem::discriminant(&s) == std::mem::discriminant(&expected)),
|
||||
@@ -254,7 +254,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_unsupported_error_out() {
|
||||
for ar in [CommonAspectRatio::WideFiveByFour, CommonAspectRatio::TallFourByFive] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(ar),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_seedream_4p5_image_request()
|
||||
@@ -269,7 +269,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_unsupported_nearest_match() {
|
||||
for strategy in [RequestMismatchMitigationStrategy::PayMoreUpgrade, RequestMismatchMitigationStrategy::PayLessDowngrade] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideFiveByFour),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_seedream_4p5_image_request()
|
||||
@@ -277,7 +277,7 @@ mod tests {
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(matches!(plan.image_size, Some(S::LandscapeSixteenNine)), "expected LandscapeSixteenNine with {:?}", strategy);
|
||||
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallFourByFive),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_seedream_4p5_image_request()
|
||||
@@ -296,7 +296,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, N::One), (2, N::Two), (3, N::Three), (4, N::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -324,7 +324,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -339,7 +339,7 @@ mod tests {
|
||||
#[test]
|
||||
fn num_images_out_of_range_clamps_to_four() {
|
||||
for strategy in [RequestMismatchMitigationStrategy::PayMoreUpgrade, RequestMismatchMitigationStrategy::PayLessDowngrade] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -355,7 +355,7 @@ mod tests {
|
||||
#[test]
|
||||
fn url_image_inputs_are_accepted_for_cost_path() {
|
||||
let urls = vec!["https://example.com/image.jpg".to_string()];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_seedream_4p5_image_request()
|
||||
};
|
||||
@@ -367,7 +367,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_is_text_to_image_mode() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_seedream_4p5_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_seedream_4p5_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream4p5(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream4p5") };
|
||||
assert!(plan.image_inputs.is_none());
|
||||
}
|
||||
@@ -375,7 +375,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_image_inputs_is_edit_mode() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_seedream_4p5_image_request()
|
||||
};
|
||||
|
||||
+7
-7
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use artcraft_api_defs::generate::image::multi_function::bytedance_seedream_5_lite_multi_function_image_gen::{
|
||||
BytedanceSeedream5LiteMultiFunctionImageGenImageSize,
|
||||
@@ -22,7 +22,7 @@ pub struct PlanArtcraftSeedream5Lite {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_artcraft_seedream_5_lite(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
@@ -157,7 +157,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_seedream_5_lite_image_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_seedream_5_lite_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream5Lite(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream5Lite") };
|
||||
assert!(plan.image_size.is_none());
|
||||
}
|
||||
@@ -165,7 +165,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto_in_edit_mode_yields_auto2k() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_seedream_5_lite_image_request()
|
||||
@@ -176,7 +176,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_auto_in_text_to_image_yields_square() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
image_inputs: None,
|
||||
..base_seedream_5_lite_image_request()
|
||||
@@ -188,7 +188,7 @@ mod tests {
|
||||
#[test]
|
||||
fn auto4k_is_mapped_to_auto3k() {
|
||||
// 5 Lite only supports up to auto_3K; auto_4K is downgraded
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto4k),
|
||||
..base_seedream_5_lite_image_request()
|
||||
};
|
||||
@@ -200,7 +200,7 @@ mod tests {
|
||||
fn num_images_direct_mapping() {
|
||||
let cases = [(1, N::One), (2, N::Two), (3, N::Three), (4, N::Four)];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_seedream_5_lite_image_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_seedream_5_lite_image_request() };
|
||||
let ImageGenerationPlan::ArtcraftSeedream5Lite(plan) = request.build().unwrap() else { panic!("expected ArtcraftSeedream5Lite") };
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_flux_1_dev_edit_image_webhook::Flux1DevEditImageNumImages;
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_1_dev_text_to_image_webhook::{
|
||||
@@ -29,7 +29,7 @@ pub struct PlanFalFlux1Dev {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_flux_1_dev(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let maybe_image_url = resolve_single_image_url(request.image_inputs.clone())?;
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_flux_1_schnell_edit_image_webhook::{
|
||||
Flux1SchnellEditImageNumImages, Flux1SchnellEditImageSize,
|
||||
@@ -32,7 +32,7 @@ pub struct PlanFalFlux1Schnell {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_flux_1_schnell(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let maybe_image_url = resolve_single_image_url(request.image_inputs.clone())?;
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_pro_11_text_to_image_webhook::{
|
||||
FluxPro11AspectRatio, FluxPro11NumImages,
|
||||
@@ -24,7 +24,7 @@ pub struct PlanFalFluxPro11 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_flux_pro_1p1(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::text::enqueue_flux_pro_11_ultra_text_to_image_webhook::{
|
||||
FluxPro11UltraAspectRatio, FluxPro11UltraNumImages,
|
||||
@@ -24,7 +24,7 @@ pub struct PlanFalFluxPro11Ultra {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_flux_pro_1p1_ultra(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
|
||||
+18
-18
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_1_edit_image_webhook::{
|
||||
EnqueueGptImage1EditImageNumImages, EnqueueGptImage1EditImageQuality,
|
||||
@@ -52,7 +52,7 @@ pub struct PlanFalGptImage1 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_gpt_image_1(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs.clone())?;
|
||||
@@ -219,8 +219,8 @@ mod tests {
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
|
||||
fn base_fal_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_fal_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage1,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
@@ -238,7 +238,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_plan(request: &GenerateImageRequest) -> PlanFalGptImage1 {
|
||||
fn build_plan(request: &GenerateImageRequestBuilder) -> PlanFalGptImage1 {
|
||||
let ImageGenerationPlan::FalGptImage1(plan) =
|
||||
plan_generate_image_fal_gpt_image_1(request).expect("plan should succeed")
|
||||
else {
|
||||
@@ -251,7 +251,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_yields_empty_urls() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.image_urls.is_empty());
|
||||
}
|
||||
@@ -262,7 +262,7 @@ mod tests {
|
||||
"https://example.com/a.jpg".to_string(),
|
||||
"https://example.com/b.jpg".to_string(),
|
||||
];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -273,7 +273,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_inputs_return_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -297,7 +297,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn image_size_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.image_size.is_none());
|
||||
}
|
||||
@@ -305,7 +305,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_auto_variants_yield_none() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(auto_ar), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(auto_ar), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.image_size.is_none(), "expected None for {:?}", auto_ar);
|
||||
}
|
||||
@@ -314,7 +314,7 @@ mod tests {
|
||||
#[test]
|
||||
fn image_size_square_variants() {
|
||||
for ar in [CommonAspectRatio::Square, CommonAspectRatio::SquareHd] {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage1ImageSize::Square)), "expected Square for {:?}", ar);
|
||||
}
|
||||
@@ -331,7 +331,7 @@ mod tests {
|
||||
CommonAspectRatio::Wide,
|
||||
];
|
||||
for ar in wide_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage1ImageSize::Horizontal)), "expected Horizontal for {:?}", ar);
|
||||
}
|
||||
@@ -348,7 +348,7 @@ mod tests {
|
||||
CommonAspectRatio::Tall,
|
||||
];
|
||||
for ar in tall_ars {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage1ImageSize::Vertical)), "expected Vertical for {:?}", ar);
|
||||
}
|
||||
@@ -363,7 +363,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_fal_request()
|
||||
@@ -378,7 +378,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_default_is_one() {
|
||||
let request = GenerateImageRequest { image_batch_count: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(matches!(plan.num_images, FalGptImage1NumImages::One));
|
||||
}
|
||||
@@ -392,7 +392,7 @@ mod tests {
|
||||
(4, FalGptImage1NumImages::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -403,7 +403,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_fal_request()
|
||||
@@ -421,7 +421,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(9),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_fal_request()
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_1p5_edit_image_webhook::{
|
||||
EnqueueGptImage1p5EditImageNumImages, EnqueueGptImage1p5EditImageQuality,
|
||||
@@ -49,7 +49,7 @@ pub struct PlanFalGptImage1p5 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_gpt_image_1p5(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs.clone())?;
|
||||
|
||||
+24
-24
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gpt_image_2_edit_image_webhook::{
|
||||
EnqueueGptImage2EditImageNumImages, EnqueueGptImage2EditImageQuality,
|
||||
@@ -53,7 +53,7 @@ pub struct PlanFalGptImage2 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_gpt_image_2(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs.clone())?;
|
||||
@@ -236,7 +236,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_yields_empty_urls() {
|
||||
let plan = build_plan(&GenerateImageRequest { image_inputs: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_inputs: None, ..base_request() });
|
||||
assert!(plan.image_urls.is_empty());
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ mod tests {
|
||||
"https://example.com/a.jpg".to_string(),
|
||||
"https://example.com/b.jpg".to_string(),
|
||||
];
|
||||
let plan = build_plan(&GenerateImageRequest {
|
||||
let plan = build_plan(&GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_request()
|
||||
});
|
||||
@@ -255,7 +255,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn media_token_inputs_return_error() {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequest {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(vec![])),
|
||||
..base_request()
|
||||
});
|
||||
@@ -276,19 +276,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn low() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::Low), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::Low), ..base_request() });
|
||||
assert!(matches!(plan.quality, FalGptImage2Quality::Low));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn medium() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::Medium), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::Medium), ..base_request() });
|
||||
assert!(matches!(plan.quality, FalGptImage2Quality::Medium));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high() {
|
||||
let plan = build_plan(&GenerateImageRequest { quality: Some(CommonQuality::High), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { quality: Some(CommonQuality::High), ..base_request() });
|
||||
assert!(matches!(plan.quality, FalGptImage2Quality::High));
|
||||
}
|
||||
}
|
||||
@@ -300,34 +300,34 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn none_yields_auto() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: None, ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Auto)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_variants_yield_auto() {
|
||||
for ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Auto)), "expected Auto for {:?}", ar);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(CommonAspectRatio::Square), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(CommonAspectRatio::Square), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Square)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_hd() {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(CommonAspectRatio::SquareHd), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(CommonAspectRatio::SquareHd), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::SquareHd)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn landscape_4x3_variants() {
|
||||
for ar in [CommonAspectRatio::WideFourByThree, CommonAspectRatio::WideFiveByFour] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Landscape4x3)), "expected Landscape4x3 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ mod tests {
|
||||
CommonAspectRatio::WideTwentyOneByNine,
|
||||
CommonAspectRatio::Wide,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Landscape16x9)), "expected Landscape16x9 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -348,7 +348,7 @@ mod tests {
|
||||
#[test]
|
||||
fn portrait_4x3_variants() {
|
||||
for ar in [CommonAspectRatio::TallThreeByFour, CommonAspectRatio::TallFourByFive] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Portrait4x3)), "expected Portrait4x3 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -361,7 +361,7 @@ mod tests {
|
||||
CommonAspectRatio::TallNineByTwentyOne,
|
||||
CommonAspectRatio::Tall,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest { aspect_ratio: Some(ar), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { aspect_ratio: Some(ar), ..base_request() });
|
||||
assert!(matches!(plan.image_size, Some(FalGptImage2ImageSize::Portrait16x9)), "expected Portrait16x9 for {:?}", ar);
|
||||
}
|
||||
}
|
||||
@@ -374,14 +374,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn default_is_one() {
|
||||
let plan = build_plan(&GenerateImageRequest { image_batch_count: None, ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_batch_count: None, ..base_request() });
|
||||
assert!(matches!(plan.num_images, FalGptImage2NumImages::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_mapping() {
|
||||
for (count, expected) in [(1, 1), (2, 2), (3, 3), (4, 4)] {
|
||||
let plan = build_plan(&GenerateImageRequest { image_batch_count: Some(count), ..base_request() });
|
||||
let plan = build_plan(&GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_request() });
|
||||
assert_eq!(plan.num_images.as_u64(), expected);
|
||||
}
|
||||
}
|
||||
@@ -393,7 +393,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequest {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_request()
|
||||
@@ -404,7 +404,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn out_of_range_error_out() {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequest {
|
||||
let result = plan_generate_image_fal_gpt_image_2(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_request()
|
||||
@@ -418,7 +418,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let plan = build_plan(&GenerateImageRequest {
|
||||
let plan = build_plan(&GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(9),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_request()
|
||||
@@ -505,8 +505,8 @@ mod tests {
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn base_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::GptImage2,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
@@ -524,7 +524,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_plan(request: &GenerateImageRequest) -> PlanFalGptImage2 {
|
||||
fn build_plan(request: &GenerateImageRequestBuilder) -> PlanFalGptImage2 {
|
||||
let ImageGenerationPlan::FalGptImage2(plan) =
|
||||
plan_generate_image_fal_gpt_image_2(request).expect("plan should succeed")
|
||||
else {
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gemini_25_flash_edit_webhook::Gemini25FlashEditAspectRatio;
|
||||
use fal_client::requests::webhook::image::text::enqueue_gemini_25_flash_text_to_image_webhook::Gemini25FlashTextToImageAspectRatio;
|
||||
@@ -31,7 +31,7 @@ pub struct PlanFalNanoBanana {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_nano_banana(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let is_edit_mode = request.image_inputs.is_some();
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_nano_banana_2_edit_image_webhook::EnqueueNanoBanana2EditImageAspectRatio;
|
||||
use fal_client::requests::webhook::image::text::enqueue_nano_banana_2_text_to_image_webhook::EnqueueNanoBanana2TextToImageAspectRatio;
|
||||
@@ -43,7 +43,7 @@ pub struct PlanFalNanaBanana2 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_nano_banana_2(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let is_edit_mode = request.image_inputs.is_some();
|
||||
|
||||
+23
-23
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_nano_banana_pro_edit_image_webhook::EnqueueNanoBananaProEditImageAspectRatio;
|
||||
use fal_client::requests::webhook::image::text::enqueue_nano_banana_pro_text_to_image_webhook::EnqueueNanoBananaProTextToImageAspectRatio;
|
||||
@@ -44,7 +44,7 @@ pub struct PlanFalNanaBananaPro {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_nano_banana_pro(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let is_edit_mode = request.image_inputs.is_some();
|
||||
@@ -244,12 +244,12 @@ mod tests {
|
||||
use crate::api::provider::Provider;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_nano_banana_pro_edit_image_webhook::EnqueueNanoBananaProEditImageAspectRatio as EditAr;
|
||||
use fal_client::requests::webhook::image::text::enqueue_nano_banana_pro_text_to_image_webhook::EnqueueNanoBananaProTextToImageAspectRatio as T2iAr;
|
||||
|
||||
fn base_fal_request() -> GenerateImageRequest {
|
||||
GenerateImageRequest {
|
||||
fn base_fal_request() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::NanoBananaPro,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
@@ -268,7 +268,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn build_plan(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> PlanFalNanaBananaPro {
|
||||
let ImageGenerationPlan::FalNanaBananaPro(plan) = plan_generate_image_fal_nano_banana_pro(request).expect("plan should succeed") else {
|
||||
panic!("expected FalNanaBananaPro variant")
|
||||
@@ -280,7 +280,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn no_image_inputs_yields_empty_urls() {
|
||||
let request = GenerateImageRequest { image_inputs: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { image_inputs: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.image_urls.is_empty());
|
||||
}
|
||||
@@ -291,7 +291,7 @@ mod tests {
|
||||
"https://example.com/a.jpg".to_string(),
|
||||
"https://example.com/b.jpg".to_string(),
|
||||
];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -302,7 +302,7 @@ mod tests {
|
||||
#[test]
|
||||
fn media_token_inputs_return_error() {
|
||||
let tokens = vec![];
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(tokens.clone())),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -317,7 +317,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn t2i_aspect_ratio_none_is_none() {
|
||||
let request = GenerateImageRequest { aspect_ratio: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.t2i_aspect_ratio.is_none());
|
||||
}
|
||||
@@ -325,7 +325,7 @@ mod tests {
|
||||
#[test]
|
||||
fn t2i_aspect_ratio_auto_falls_back_to_square() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: None,
|
||||
..base_fal_request()
|
||||
@@ -356,7 +356,7 @@ mod tests {
|
||||
(CommonAspectRatio::Tall, T2iAr::NineBySixteen),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { aspect_ratio: Some(common), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { aspect_ratio: Some(common), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(
|
||||
matches!(plan.t2i_aspect_ratio, Some(ar) if std::mem::discriminant(&ar) == std::mem::discriminant(&expected)),
|
||||
@@ -367,7 +367,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn t2i_aspect_ratio_unsupported_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
..base_fal_request()
|
||||
@@ -385,7 +385,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineByTwentyOne),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
..base_fal_request()
|
||||
@@ -404,7 +404,7 @@ mod tests {
|
||||
fn edit_aspect_ratio_auto_in_edit_mode_yields_auto() {
|
||||
let urls = vec!["https://example.com/img.jpg".to_string()];
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: Some(ImageListRef::Urls(urls.clone())),
|
||||
..base_fal_request()
|
||||
@@ -420,7 +420,7 @@ mod tests {
|
||||
#[test]
|
||||
fn edit_aspect_ratio_auto_in_text_to_image_falls_back_to_square() {
|
||||
for auto_ar in [CommonAspectRatio::Auto, CommonAspectRatio::Auto2k, CommonAspectRatio::Auto4k] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(auto_ar),
|
||||
image_inputs: None,
|
||||
..base_fal_request()
|
||||
@@ -437,7 +437,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_none_is_none() {
|
||||
let request = GenerateImageRequest { resolution: None, ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: None, ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(plan.resolution.is_none());
|
||||
}
|
||||
@@ -450,7 +450,7 @@ mod tests {
|
||||
(CommonResolution::FourK, FalNbpResolution::FourK),
|
||||
];
|
||||
for (common, expected) in cases {
|
||||
let request = GenerateImageRequest { resolution: Some(common), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { resolution: Some(common), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(
|
||||
matches!(plan.resolution, Some(r) if std::mem::discriminant(&r) == std::mem::discriminant(&expected)),
|
||||
@@ -461,7 +461,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn resolution_three_k_falls_back_to_two_k() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
resolution: Some(CommonResolution::ThreeK),
|
||||
..base_fal_request()
|
||||
};
|
||||
@@ -478,7 +478,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(0),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
@@ -501,7 +501,7 @@ mod tests {
|
||||
(4, FalNbpNumImages::Four),
|
||||
];
|
||||
for (count, expected) in cases {
|
||||
let request = GenerateImageRequest { image_batch_count: Some(count), ..base_fal_request() };
|
||||
let request = GenerateImageRequestBuilder { image_batch_count: Some(count), ..base_fal_request() };
|
||||
let plan = build_plan(&request);
|
||||
assert!(
|
||||
std::mem::discriminant(&plan.num_images) == std::mem::discriminant(&expected),
|
||||
@@ -512,7 +512,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn num_images_out_of_range_error_out() {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
@@ -531,7 +531,7 @@ mod tests {
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
] {
|
||||
let request = GenerateImageRequest {
|
||||
let request = GenerateImageRequestBuilder {
|
||||
quality: None,
|
||||
image_batch_count: Some(5),
|
||||
request_mismatch_mitigation_strategy: strategy,
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v4_edit_image_webhook::{
|
||||
EnqueueBytedanceSeedreamV4EditImageNumImages, EnqueueBytedanceSeedreamV4EditImageSize,
|
||||
@@ -44,7 +44,7 @@ pub struct PlanFalSeedream4 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_seedream_4(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let is_edit_mode = request.image_inputs.is_some();
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v4p5_edit_image_webhook::{
|
||||
EnqueueBytedanceSeedreamV4p5EditImageNumImages, EnqueueBytedanceSeedreamV4p5EditImageSize,
|
||||
@@ -42,7 +42,7 @@ pub struct PlanFalSeedream4p5 {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_seedream_4p5(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs.clone())?;
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_bytedance_seedream_v5_lite_edit_image_webhook::{
|
||||
EnqueueBytedanceSeedreamV5LiteEditImageNumImages, EnqueueBytedanceSeedreamV5LiteEditImageSize,
|
||||
@@ -43,7 +43,7 @@ pub struct PlanFalSeedream5Lite {
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_seedream_5_lite(
|
||||
request: &GenerateImageRequest,
|
||||
request: &GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationPlan, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs.clone())?;
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
use crate::api::provider::Provider;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_image::image_generation_cost_estimate::ImageGenerationCostEstimate;
|
||||
use crate::generate::generate_image_v2::image_generation_draft_context::ImageGenerationDraftContext;
|
||||
use crate::generate::generate_image_v2::image_generation_request::ImageGenerationRequest;
|
||||
|
||||
/// Wrapper for all image generation draft requests.
|
||||
///
|
||||
/// Drafts hold validated/planned parameters but may still need media resolution
|
||||
/// (e.g. uploading local files to a provider) before they can be sent.
|
||||
/// Currently empty — FAL doesn't need a draft phase.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImageGenerationDraftRequest {
|
||||
}
|
||||
|
||||
impl ImageGenerationDraftRequest {
|
||||
pub fn get_provider(&self) -> Provider {
|
||||
match *self {}
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> Result<ImageGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match *self {}
|
||||
}
|
||||
|
||||
pub async fn finalize(self, _draft_context: ImageGenerationDraftContext<'_>) -> Result<ImageGenerationRequest, ArtcraftRouterError> {
|
||||
match self {}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Context passed when finalizing a draft into a concrete request.
|
||||
///
|
||||
/// Currently empty — FAL doesn't need a draft phase so no context is required.
|
||||
/// Future providers that need media uploads during finalization will add fields here
|
||||
/// (e.g. a router client reference, media-file-to-URL maps, etc.).
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ImageGenerationDraftContext<'a> {
|
||||
/// Prevent construction without Default; reserving the lifetime for future use.
|
||||
_phantom: std::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl Debug for ImageGenerationDraftContext<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImageGenerationDraftContext").finish()
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
use crate::api::provider::Provider;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_image::image_generation_cost_estimate::ImageGenerationCostEstimate;
|
||||
use crate::generate::generate_image_v2::image_generation_draft::ImageGenerationDraftRequest;
|
||||
use crate::generate::generate_image_v2::image_generation_request::ImageGenerationRequest;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ImageGenerationDraftOrRequest {
|
||||
Draft(ImageGenerationDraftRequest),
|
||||
Request(ImageGenerationRequest),
|
||||
}
|
||||
|
||||
impl ImageGenerationDraftOrRequest {
|
||||
pub fn get_provider(&self) -> Provider {
|
||||
match self {
|
||||
Self::Draft(draft) => draft.get_provider(),
|
||||
Self::Request(request) => request.get_provider(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> Result<ImageGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match self {
|
||||
Self::Draft(draft) => draft.estimate_cost(),
|
||||
Self::Request(request) => request.estimate_cost(),
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_image::generate_image_response::GenerateImageResponse;
|
||||
use crate::generate::generate_image::image_generation_cost_estimate::ImageGenerationCostEstimate;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_dev::cost::FalFlux1DevCostState;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_dev::request::FalFlux1DevRequestState;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_schnell::cost::FalFlux1SchnellCostState;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_schnell::request::FalFlux1SchnellRequestState;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_2::cost::FalNanoBanana2CostState;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_2::request::FalNanoBanana2RequestState;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_pro::cost::FalNanoBananaProCostState;
|
||||
use crate::generate::generate_image_v2::providers::fal::nano_banana_pro::request::FalNanoBananaProRequestState;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImageGenerationRequest {
|
||||
FalFlux1Dev(FalFlux1DevRequestState),
|
||||
FalFlux1Schnell(FalFlux1SchnellRequestState),
|
||||
FalNanoBanana2(FalNanoBanana2RequestState),
|
||||
FalNanoBananaPro(FalNanoBananaProRequestState),
|
||||
}
|
||||
|
||||
impl ImageGenerationRequest {
|
||||
pub fn get_provider(&self) -> Provider {
|
||||
match self {
|
||||
Self::FalFlux1Dev(_) => Provider::Fal,
|
||||
Self::FalFlux1Schnell(_) => Provider::Fal,
|
||||
Self::FalNanoBanana2(_) => Provider::Fal,
|
||||
Self::FalNanoBananaPro(_) => Provider::Fal,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> Result<ImageGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match self {
|
||||
Self::FalFlux1Dev(request) => {
|
||||
Ok(FalFlux1DevCostState::from_request(request).estimate_cost())
|
||||
}
|
||||
Self::FalFlux1Schnell(request) => {
|
||||
Ok(FalFlux1SchnellCostState::from_request(request).estimate_cost())
|
||||
}
|
||||
Self::FalNanoBanana2(request) => {
|
||||
Ok(FalNanoBanana2CostState::from_request(request).estimate_cost())
|
||||
}
|
||||
Self::FalNanoBananaPro(request) => {
|
||||
Ok(FalNanoBananaProCostState::from_request(request).estimate_cost())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_request(&self, client: &RouterClient) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
match self {
|
||||
Self::FalFlux1Dev(request) => {
|
||||
let fal_client = client.get_fal_webhook_optional_client_ref()?;
|
||||
request.send(fal_client).await
|
||||
}
|
||||
Self::FalFlux1Schnell(request) => {
|
||||
let fal_client = client.get_fal_webhook_optional_client_ref()?;
|
||||
request.send(fal_client).await
|
||||
}
|
||||
Self::FalNanoBanana2(request) => {
|
||||
let fal_client = client.get_fal_webhook_optional_client_ref()?;
|
||||
request.send(fal_client).await
|
||||
}
|
||||
Self::FalNanoBananaPro(request) => {
|
||||
let fal_client = client.get_fal_webhook_optional_client_ref()?;
|
||||
request.send(fal_client).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod image_generation_draft;
|
||||
pub mod image_generation_draft_context;
|
||||
pub mod image_generation_draft_or_request;
|
||||
pub mod image_generation_request;
|
||||
pub mod providers;
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
use fal_client::requests::api::image::edit::flux_1_dev_edit_image::api::{
|
||||
Flux1DevEditImageNumImages, Flux1DevEditImageRequest,
|
||||
};
|
||||
use fal_client::requests::api::image::text::flux_1_dev_text_to_image::api::{
|
||||
Flux1DevTextToImageAspectRatio, Flux1DevTextToImageNumImages, Flux1DevTextToImageRequest,
|
||||
};
|
||||
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request_builder::GenerateImageRequestBuilder;
|
||||
use crate::generate::generate_image_v2::image_generation_draft_or_request::ImageGenerationDraftOrRequest;
|
||||
use crate::generate::generate_image_v2::image_generation_request::ImageGenerationRequest;
|
||||
use crate::generate::generate_image_v2::providers::fal::flux_1_dev::request::FalFlux1DevRequestState;
|
||||
|
||||
pub fn build_fal_flux_1_dev(
|
||||
builder: GenerateImageRequestBuilder,
|
||||
) -> Result<ImageGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let strategy = builder.request_mismatch_mitigation_strategy;
|
||||
|
||||
let prompt = builder.prompt.clone().unwrap_or_default();
|
||||
let num_images = plan_num_images(builder.image_batch_count, strategy)?;
|
||||
let image_url = resolve_single_image_url(builder.image_inputs.clone())?;
|
||||
|
||||
let state = if let Some(url) = image_url {
|
||||
// Edit image (single image URL, no aspect ratio / resolution controls)
|
||||
FalFlux1DevRequestState::EditImage(Flux1DevEditImageRequest {
|
||||
prompt,
|
||||
image_url: url,
|
||||
num_images: to_edit_num_images(num_images),
|
||||
})
|
||||
} else {
|
||||
// Text-to-image
|
||||
let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio);
|
||||
|
||||
FalFlux1DevRequestState::TextToImage(Flux1DevTextToImageRequest {
|
||||
prompt,
|
||||
num_images: to_t2i_num_images(num_images),
|
||||
aspect_ratio,
|
||||
})
|
||||
};
|
||||
|
||||
Ok(ImageGenerationDraftOrRequest::Request(
|
||||
ImageGenerationRequest::FalFlux1Dev(state),
|
||||
))
|
||||
}
|
||||
|
||||
// ── Num images ──
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum PlannedNumImages {
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
fn plan_num_images(
|
||||
count: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<PlannedNumImages, ArtcraftRouterError> {
|
||||
let count = count.unwrap_or(1);
|
||||
match count {
|
||||
0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)),
|
||||
1 => Ok(PlannedNumImages::One),
|
||||
2 => Ok(PlannedNumImages::Two),
|
||||
3 => Ok(PlannedNumImages::Three),
|
||||
4 => Ok(PlannedNumImages::Four),
|
||||
_ => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "image_batch_count",
|
||||
value: format!("{}", count),
|
||||
}))
|
||||
}
|
||||
_ => Ok(PlannedNumImages::Four),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn to_t2i_num_images(n: PlannedNumImages) -> Flux1DevTextToImageNumImages {
|
||||
match n {
|
||||
PlannedNumImages::One => Flux1DevTextToImageNumImages::One,
|
||||
PlannedNumImages::Two => Flux1DevTextToImageNumImages::Two,
|
||||
PlannedNumImages::Three => Flux1DevTextToImageNumImages::Three,
|
||||
PlannedNumImages::Four => Flux1DevTextToImageNumImages::Four,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_edit_num_images(n: PlannedNumImages) -> Flux1DevEditImageNumImages {
|
||||
match n {
|
||||
PlannedNumImages::One => Flux1DevEditImageNumImages::One,
|
||||
PlannedNumImages::Two => Flux1DevEditImageNumImages::Two,
|
||||
PlannedNumImages::Three => Flux1DevEditImageNumImages::Three,
|
||||
PlannedNumImages::Four => Flux1DevEditImageNumImages::Four,
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aspect ratio ──
|
||||
|
||||
fn plan_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
) -> Flux1DevTextToImageAspectRatio {
|
||||
use Flux1DevTextToImageAspectRatio as T;
|
||||
match aspect_ratio {
|
||||
None | Some(CommonAspectRatio::Auto) | Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto3k) | Some(CommonAspectRatio::Auto4k) => T::SquareHd,
|
||||
Some(CommonAspectRatio::Square) => T::Square,
|
||||
Some(CommonAspectRatio::SquareHd) => T::SquareHd,
|
||||
Some(CommonAspectRatio::WideFourByThree) | Some(CommonAspectRatio::WideFiveByFour)
|
||||
| Some(CommonAspectRatio::WideThreeByTwo) | Some(CommonAspectRatio::Wide) => T::LandscapeFourByThree,
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::WideTwentyOneByNine) => T::LandscapeSixteenByNine,
|
||||
Some(CommonAspectRatio::TallThreeByFour) | Some(CommonAspectRatio::TallFourByFive)
|
||||
| Some(CommonAspectRatio::TallTwoByThree) | Some(CommonAspectRatio::Tall) => T::PortraitThreeByFour,
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::TallNineByTwentyOne) => T::PortraitNineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
// ── Image inputs ──
|
||||
|
||||
/// Flux 1 Dev edit takes a single image URL, not a list.
|
||||
/// If multiple URLs are provided, we take the first one.
|
||||
fn resolve_single_image_url(
|
||||
image_inputs: Option<ImageListRef>,
|
||||
) -> Result<Option<String>, ArtcraftRouterError> {
|
||||
match image_inputs {
|
||||
None => Ok(None),
|
||||
Some(ImageListRef::Urls(urls)) => {
|
||||
Ok(urls.into_iter().next())
|
||||
}
|
||||
Some(ImageListRef::MediaFileTokens(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::api::common_image_model::CommonImageModel;
|
||||
use crate::api::provider::Provider;
|
||||
|
||||
fn base_builder() -> GenerateImageRequestBuilder {
|
||||
GenerateImageRequestBuilder {
|
||||
model: CommonImageModel::Flux1Dev,
|
||||
provider: Provider::Fal,
|
||||
prompt: Some("a cat in space".to_string()),
|
||||
image_inputs: None,
|
||||
resolution: None,
|
||||
aspect_ratio: None,
|
||||
quality: None,
|
||||
image_batch_count: None,
|
||||
horizontal_angle: None,
|
||||
vertical_angle: None,
|
||||
zoom: None,
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
generation_mode_mismatch_strategy: None,
|
||||
idempotency_token: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_t2i(result: Result<ImageGenerationDraftOrRequest, ArtcraftRouterError>) -> Flux1DevTextToImageRequest {
|
||||
let ImageGenerationDraftOrRequest::Request(
|
||||
ImageGenerationRequest::FalFlux1Dev(
|
||||
FalFlux1DevRequestState::TextToImage(req)
|
||||
)
|
||||
) = result.expect("build should succeed") else {
|
||||
panic!("expected TextToImage variant")
|
||||
};
|
||||
req
|
||||
}
|
||||
|
||||
fn unwrap_edit(result: Result<ImageGenerationDraftOrRequest, ArtcraftRouterError>) -> Flux1DevEditImageRequest {
|
||||
let ImageGenerationDraftOrRequest::Request(
|
||||
ImageGenerationRequest::FalFlux1Dev(
|
||||
FalFlux1DevRequestState::EditImage(req)
|
||||
)
|
||||
) = result.expect("build should succeed") else {
|
||||
panic!("expected EditImage variant")
|
||||
};
|
||||
req
|
||||
}
|
||||
|
||||
// ── Mode detection ──
|
||||
|
||||
mod mode_detection {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn no_images_yields_text_to_image() {
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(base_builder()));
|
||||
assert_eq!(req.prompt, "a cat in space");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_url_yields_edit_image() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(vec!["https://example.com/img.jpg".to_string()])),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_edit(build_fal_flux_1_dev(builder));
|
||||
assert_eq!(req.image_url, "https://example.com/img.jpg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_urls_takes_first() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(vec![
|
||||
"https://example.com/a.jpg".to_string(),
|
||||
"https://example.com/b.jpg".to_string(),
|
||||
])),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_edit(build_fal_flux_1_dev(builder));
|
||||
assert_eq!(req.image_url, "https://example.com/a.jpg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_urls_yields_text_to_image() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(vec![])),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert_eq!(req.prompt, "a cat in space");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn media_tokens_return_error() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::MediaFileTokens(vec![])),
|
||||
..base_builder()
|
||||
};
|
||||
assert!(matches!(
|
||||
build_fal_flux_1_dev(builder),
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Num images ──
|
||||
|
||||
mod num_images_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_is_one() {
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(base_builder()));
|
||||
assert!(matches!(req.num_images, Flux1DevTextToImageNumImages::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_three() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(3),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.num_images, Flux1DevTextToImageNumImages::Three));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_is_error() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(0),
|
||||
..base_builder()
|
||||
};
|
||||
assert!(matches!(
|
||||
build_fal_flux_1_dev(builder),
|
||||
Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_four_error_out() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(7),
|
||||
..base_builder()
|
||||
};
|
||||
assert!(matches!(
|
||||
build_fal_flux_1_dev(builder),
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. }))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_four_clamps_with_upgrade() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_batch_count: Some(7),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.num_images, Flux1DevTextToImageNumImages::Four));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_mode_num_images() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
image_inputs: Some(ImageListRef::Urls(vec!["https://example.com/img.jpg".to_string()])),
|
||||
image_batch_count: Some(2),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_edit(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.num_images, Flux1DevEditImageNumImages::Two));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aspect ratio ──
|
||||
|
||||
mod aspect_ratio_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_is_square_hd() {
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(base_builder()));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::SquareHd));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_yields_square_hd() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Auto),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::SquareHd));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::Square),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::Square));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_hd() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::SquareHd),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::SquareHd));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_four_by_three() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideFourByThree),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::LandscapeFourByThree));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_sixteen_by_nine() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::LandscapeSixteenByNine));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_twenty_one_by_nine_maps_to_sixteen_by_nine() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::WideTwentyOneByNine),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::LandscapeSixteenByNine));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_three_by_four() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallThreeByFour),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::PortraitThreeByFour));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tall_nine_by_sixteen() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert!(matches!(req.aspect_ratio, Flux1DevTextToImageAspectRatio::PortraitNineBySixteen));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Prompt ──
|
||||
|
||||
mod prompt_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn prompt_is_passed_through() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
prompt: Some("my custom prompt".to_string()),
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert_eq!(req.prompt, "my custom prompt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_prompt_defaults_to_empty() {
|
||||
let builder = GenerateImageRequestBuilder {
|
||||
prompt: None,
|
||||
..base_builder()
|
||||
};
|
||||
let req = unwrap_t2i(build_fal_flux_1_dev(builder));
|
||||
assert_eq!(req.prompt, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user