1use serde::{Deserialize, Serialize};
2
3const DEFAULT_STEPS: u32 = 23;
4const DEFAULT_SCALE: f32 = 5.0;
5const QUALITY_TAGS: &str = ", very aesthetic, masterpiece, no text";
6const UC_PRESET_STRONG: &str = ", lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page, ";
7const UC_PRESET_LIGHT: &str = ", lowres, artistic error, scan artifacts, worst quality, bad quality, jpeg artifacts, multiple views, very displeasing, too many watermarks, negative space, blank page, ";
8const UC_PRESET_FURRY_FOCUS: &str = ", {worst quality}, distracting watermark, unfinished, bad quality, {widescreen}, upscale, {sequence}, {{grandfathered content}}, blurred foreground, chromatic aberration, sketch, everyone, [sketch background], simple, [flat colors], ych (character), outline, multiple scenes, [[horror (theme)]], comic, ";
9const UC_PRESET_HUMAN_FOCUS: &str = ", lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page, @_@, mismatched pupils, glowing eyes, bad anatomy, ";
10
11#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub enum ApiKeySource {
15 Environment,
17 Inline { value: String },
19}
20
21#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
23pub enum Model {
24 #[serde(rename = "nai-diffusion-4-5-full")]
26 #[default]
27 NaiDiffusion45Full,
28 #[serde(rename = "nai-diffusion-4-5-curated")]
30 NaiDiffusion45Curated,
31 #[serde(rename = "nai-diffusion-4-full")]
33 NaiDiffusion4Full,
34 #[serde(rename = "nai-diffusion-4-curated")]
36 NaiDiffusion4Curated,
37 #[serde(rename = "nai-diffusion-3")]
39 NaiDiffusion3,
40 #[serde(rename = "nai-diffusion-3-furry")]
42 NaiDiffusion3Furry,
43}
44
45impl Model {
46 pub fn as_str(&self) -> &'static str {
48 match self {
49 Self::NaiDiffusion45Full => "nai-diffusion-4-5-full",
50 Self::NaiDiffusion45Curated => "nai-diffusion-4-5-curated",
51 Self::NaiDiffusion4Full => "nai-diffusion-4-full",
52 Self::NaiDiffusion4Curated => "nai-diffusion-4-curated",
53 Self::NaiDiffusion3 => "nai-diffusion-3",
54 Self::NaiDiffusion3Furry => "nai-diffusion-3-furry",
55 }
56 }
57
58 pub fn is_v4(&self) -> bool {
60 matches!(
61 self,
62 Self::NaiDiffusion45Full
63 | Self::NaiDiffusion45Curated
64 | Self::NaiDiffusion4Full
65 | Self::NaiDiffusion4Curated
66 )
67 }
68
69 pub fn is_v45(&self) -> bool {
71 matches!(self, Self::NaiDiffusion45Full | Self::NaiDiffusion45Curated)
72 }
73
74 pub fn vibe_model_key(&self) -> &'static str {
76 match self {
77 Self::NaiDiffusion45Full => "v4-5full",
78 Self::NaiDiffusion45Curated => "v4-5curated",
79 Self::NaiDiffusion4Full => "v4full",
80 Self::NaiDiffusion4Curated => "v4curated",
81 Self::NaiDiffusion3 => "v3",
82 Self::NaiDiffusion3Furry => "v3furry",
83 }
84 }
85}
86
87#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
89pub enum Sampler {
90 #[serde(rename = "k_euler")]
92 KEuler,
93 #[serde(rename = "k_euler_ancestral")]
95 #[default]
96 KEulerAncestral,
97 #[serde(rename = "k_dpm_2")]
99 KDpm2,
100 #[serde(rename = "k_dpm_2_ancestral")]
102 KDpm2Ancestral,
103 #[serde(rename = "k_dpmpp_2m")]
105 KDpmpp2m,
106 #[serde(rename = "k_dpmpp_2s_ancestral")]
108 KDpmpp2sAncestral,
109 #[serde(rename = "k_dpmpp_sde")]
111 KDpmppSde,
112 #[serde(rename = "ddim")]
114 Ddim,
115}
116
117impl Sampler {
118 pub fn as_str(&self) -> &'static str {
120 match self {
121 Self::KEuler => "k_euler",
122 Self::KEulerAncestral => "k_euler_ancestral",
123 Self::KDpm2 => "k_dpm_2",
124 Self::KDpm2Ancestral => "k_dpm_2_ancestral",
125 Self::KDpmpp2m => "k_dpmpp_2m",
126 Self::KDpmpp2sAncestral => "k_dpmpp_2s_ancestral",
127 Self::KDpmppSde => "k_dpmpp_sde",
128 Self::Ddim => "ddim",
129 }
130 }
131}
132
133#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
135pub enum NoiseSchedule {
136 #[serde(rename = "karras")]
138 #[default]
139 Karras,
140 #[serde(rename = "exponential")]
142 Exponential,
143 #[serde(rename = "polyexponential")]
145 Polyexponential,
146}
147
148impl NoiseSchedule {
149 pub fn as_str(&self) -> &'static str {
151 match self {
152 Self::Karras => "karras",
153 Self::Exponential => "exponential",
154 Self::Polyexponential => "polyexponential",
155 }
156 }
157}
158
159#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
161#[serde(rename_all = "snake_case")]
162pub enum UcPreset {
163 Strong,
165 #[default]
167 Light,
168 FurryFocus,
170 HumanFocus,
172 None,
174}
175
176impl UcPreset {
177 pub fn as_api_value(&self) -> i32 {
179 match self {
180 Self::Strong => 0,
181 Self::Light => 1,
182 Self::FurryFocus => 2,
183 Self::HumanFocus => 3,
184 Self::None => 4,
185 }
186 }
187
188 pub fn preset_text(&self) -> &'static str {
190 match self {
191 Self::Strong => UC_PRESET_STRONG,
192 Self::Light => UC_PRESET_LIGHT,
193 Self::FurryFocus => UC_PRESET_FURRY_FOCUS,
194 Self::HumanFocus => UC_PRESET_HUMAN_FOCUS,
195 Self::None => "",
196 }
197 }
198}
199
200#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
202#[serde(rename_all = "snake_case")]
203pub enum StreamMode {
204 #[default]
206 Sse,
207}
208
209impl StreamMode {
210 pub fn as_str(&self) -> &'static str {
212 match self {
213 Self::Sse => "sse",
214 }
215 }
216}
217
218#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
220pub enum ImageFormat {
221 #[serde(rename = "png")]
223 Png,
224 #[serde(rename = "webp")]
226 Webp,
227}
228
229impl ImageFormat {
230 pub fn as_str(&self) -> &'static str {
232 match self {
233 Self::Png => "png",
234 Self::Webp => "webp",
235 }
236 }
237}
238
239#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
241pub struct ImageSize {
242 pub width: u32,
244 pub height: u32,
246}
247
248impl ImageSize {
249 pub fn portrait() -> Self {
251 Self {
252 width: 832,
253 height: 1216,
254 }
255 }
256
257 pub fn landscape() -> Self {
259 Self {
260 width: 1216,
261 height: 832,
262 }
263 }
264
265 pub fn square() -> Self {
267 Self {
268 width: 1024,
269 height: 1024,
270 }
271 }
272
273 pub fn large_portrait() -> Self {
275 Self {
276 width: 1024,
277 height: 1536,
278 }
279 }
280
281 pub fn large_landscape() -> Self {
283 Self {
284 width: 1536,
285 height: 1024,
286 }
287 }
288}
289
290impl Default for ImageSize {
291 fn default() -> Self {
292 Self::portrait()
293 }
294}
295
296#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
298pub struct CharacterPosition {
299 pub x: f32,
301 pub y: f32,
303}
304
305impl Default for CharacterPosition {
306 fn default() -> Self {
307 Self { x: 0.5, y: 0.5 }
308 }
309}
310
311#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
313pub struct Character {
314 pub prompt: String,
316 pub negative_prompt: Option<String>,
318 pub position: CharacterPosition,
320 pub enabled: bool,
322}
323
324#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
326pub enum CharacterReferenceType {
327 #[serde(rename = "character")]
329 Character,
330 #[serde(rename = "style")]
332 Style,
333 #[serde(rename = "character&style")]
335 CharacterAndStyle,
336}
337
338#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
340pub struct CharacterReference {
341 pub image: String,
343 pub reference_type: CharacterReferenceType,
345 pub fidelity: f32,
347 pub strength: f32,
349}
350
351#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
353pub struct Img2ImgRequest {
354 pub image: String,
356 pub strength: f32,
358 pub noise: f32,
360 pub mask: Option<String>,
362}
363
364#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
366pub struct ControlNetInput {
367 pub image: String,
369 pub info_extracted: f32,
371 pub strength: f32,
373 pub model: Model,
375 pub vibe_data_cache: Option<String>,
377}
378
379#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
381pub struct ControlNetConfig {
382 pub images: Vec<ControlNetInput>,
384 pub strength: f32,
386}
387
388#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
390pub struct EncodeVibeRequest {
391 pub image: String,
393 pub information_extracted: f32,
395 pub model: Model,
397}
398
399#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
401#[serde(rename_all = "kebab-case")]
402pub enum DirectorTool {
403 Lineart,
405 Sketch,
407 BgRemoval,
409 Emotion,
411 Declutter,
413 Colorize,
415}
416
417#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
419pub struct RunDirectorToolRequest {
420 pub tool: DirectorTool,
422 pub image: String,
424 pub prompt: Option<String>,
426 pub defry: Option<u8>,
428}
429
430#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
432pub struct GenerateImageRequest {
433 pub prompt: String,
435 pub model: Model,
437 pub size: ImageSize,
439 pub negative_prompt: Option<String>,
441 pub quality: bool,
443 pub uc_preset: UcPreset,
445 pub steps: u32,
447 pub scale: f32,
449 pub sampler: Sampler,
451 pub noise_schedule: NoiseSchedule,
453 pub seed: i64,
455 pub n_samples: u32,
457 pub cfg_rescale: f32,
459 pub variety_boost: bool,
461 pub i2i: Option<Img2ImgRequest>,
463 pub controlnet: Option<ControlNetConfig>,
465 pub character_references: Option<Vec<CharacterReference>>,
467 pub characters: Option<Vec<Character>>,
469 pub use_coords: Option<bool>,
471 pub image_format: Option<ImageFormat>,
473}
474
475impl Default for GenerateImageRequest {
476 fn default() -> Self {
477 Self {
478 prompt: String::new(),
479 model: Model::default(),
480 size: ImageSize::default(),
481 negative_prompt: None,
482 quality: true,
483 uc_preset: UcPreset::default(),
484 steps: DEFAULT_STEPS,
485 scale: DEFAULT_SCALE,
486 sampler: Sampler::default(),
487 noise_schedule: NoiseSchedule::default(),
488 seed: 0,
489 n_samples: 1,
490 cfg_rescale: 0.0,
491 variety_boost: false,
492 i2i: None,
493 controlnet: None,
494 character_references: None,
495 characters: None,
496 use_coords: None,
497 image_format: None,
498 }
499 }
500}
501
502impl GenerateImageRequest {
503 pub fn processed_prompt(&self) -> String {
505 if self.quality {
506 format!("{}{}", self.prompt, QUALITY_TAGS)
507 } else {
508 self.prompt.clone()
509 }
510 }
511
512 pub fn processed_negative_prompt(&self) -> String {
514 format!(
515 "{}{}",
516 self.negative_prompt.clone().unwrap_or_default(),
517 self.uc_preset.preset_text()
518 )
519 }
520}
521
522#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
524pub struct GenerateImageStreamRequest {
525 pub base: GenerateImageRequest,
527 pub stream: StreamMode,
529}
530
531#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
533pub struct GeneratedImage {
534 pub bytes: Vec<u8>,
536 pub mime_type: Option<String>,
538 pub seed: Option<i64>,
540}
541
542#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
544pub struct ImageStreamChunk {
545 pub event_type: String,
547 pub samp_ix: u32,
549 pub step_ix: Option<u32>,
551 pub gen_id: u32,
553 pub sigma: Option<f32>,
555 pub image: String,
557}
558
559impl ImageStreamChunk {
560 pub fn from_sse_line(line: &str) -> Result<Self, serde_json::Error> {
562 let payload = line
563 .strip_prefix("data:")
564 .map(str::trim_start)
565 .unwrap_or(line);
566 serde_json::from_str(payload)
567 }
568}
569
570#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
572pub struct SubscriptionInfo {
573 pub anlas_balance: i64,
575 pub is_opus: bool,
577 pub tier: i32,
579 pub tier_name: String,
581 pub expires_at_ms: Option<u64>,
583}