Skip to main content

context69_contracts/
translation.rs

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}