1use chrono::{DateTime, Utc};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use utoipa::{IntoParams, ToSchema};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
8pub struct TranslationDirective {
9 #[serde(default, skip_serializing_if = "Option::is_none")]
10 pub source_locale: Option<String>,
11 #[serde(default)]
12 pub target_locales: Vec<String>,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
16#[serde(rename_all = "snake_case")]
17pub enum TranslationStatus {
18 Queued,
19 Running,
20 Succeeded,
21 Failed,
22 Skipped,
23 QuotaExceeded,
24 Unavailable,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
28#[serde(rename_all = "snake_case")]
29pub enum TranslationProviderKind {
30 Deepl,
31 Llm,
32 Libretranslate,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
36#[serde(rename_all = "snake_case")]
37pub enum TranslationLlmApiKind {
38 OpenaiResponses,
39 OpenaiChatCompletions,
40 AnthropicMessages,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, JsonSchema)]
44#[serde(rename_all = "snake_case")]
45pub enum DeeplPlan {
46 Free,
47 Pro,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
51pub struct TranslationProviderInput {
52 pub provider: TranslationProviderKind,
53 #[serde(default)]
54 pub enabled: bool,
55 pub priority: i32,
56 #[serde(default, skip_serializing_if = "Option::is_none")]
57 pub endpoint: Option<String>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub api_key: Option<String>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub model: Option<String>,
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub llm_api_kind: Option<TranslationLlmApiKind>,
64 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub deepl_plan: Option<DeeplPlan>,
66 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub monthly_character_limit: Option<i64>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
71pub struct TranslationProviderResponse {
72 pub provider: TranslationProviderKind,
73 pub enabled: bool,
74 pub priority: i32,
75 pub endpoint: Option<String>,
76 pub has_api_key: bool,
77 pub model: Option<String>,
78 pub llm_api_kind: Option<TranslationLlmApiKind>,
79 pub deepl_plan: Option<DeeplPlan>,
80 pub monthly_character_limit: Option<i64>,
81 pub current_month_characters: i64,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
85pub struct UpdateTranslationSettingsRequest {
86 pub providers: Vec<TranslationProviderInput>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
90pub struct TranslationSettingsResponse {
91 pub providers: Vec<TranslationProviderResponse>,
92}
93
94#[derive(Debug, Clone, Deserialize, IntoParams, ToSchema)]
95#[into_params(parameter_in = Query)]
96pub struct TranslationProviderPageQuery {
97 #[serde(default = "default_page")]
98 pub page: u32,
99 #[serde(default = "default_page_size")]
100 pub page_size: u32,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
104pub struct TranslationProviderPageResponse {
105 pub items: Vec<TranslationProviderResponse>,
106 pub pagination: crate::Pagination,
107}
108
109const fn default_page() -> u32 {
110 1
111}
112
113const fn default_page_size() -> u32 {
114 50
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
118pub struct TranslationGlossaryEntry {
119 pub source: String,
120 pub target: String,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
124pub struct UpdateGroupTranslationSettingsRequest {
125 pub enabled: bool,
126 #[serde(default)]
127 pub default_target_locales: Vec<String>,
128 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub source_locale: Option<String>,
130 #[serde(default)]
131 pub glossary: Vec<TranslationGlossaryEntry>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
135pub struct GroupTranslationSettingsResponse {
136 pub enabled: bool,
137 pub default_target_locales: Vec<String>,
138 pub source_locale: Option<String>,
139 pub glossary: Vec<TranslationGlossaryEntry>,
140 pub queued_count: i64,
141 pub running_count: i64,
142 pub succeeded_count: i64,
143 pub failed_count: i64,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
147pub struct TranslationJobResponse {
148 pub job_id: Uuid,
149 pub document_id: i64,
150 pub target_locale: String,
151 pub source_locale: Option<String>,
152 pub status: TranslationStatus,
153 pub provider: Option<TranslationProviderKind>,
154 pub attempt_count: i32,
155 pub source_character_count: i64,
156 pub error_message: Option<String>,
157 pub created_at: DateTime<Utc>,
158 pub started_at: Option<DateTime<Utc>>,
159 pub finished_at: Option<DateTime<Utc>>,
160 pub updated_at: DateTime<Utc>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
164pub struct RebuildDocumentTranslationsRequest {
165 #[serde(default)]
166 pub target_locales: Vec<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
170pub struct TranslationJobsResponse {
171 pub jobs: Vec<TranslationJobResponse>,
172}