1use crate::prelude::*;
2
3#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Type)]
4#[cfg_attr(feature = "ts_rs", derive(TS))]
5#[sqlx(type_name = "reasoning_effort_level", rename_all = "snake_case")]
6#[serde(rename_all = "snake_case")]
7pub enum ReasoningEffortLevel {
8 Minimal,
9 Low,
10 Medium,
11 High,
12}
13
14#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Type)]
15#[cfg_attr(feature = "ts_rs", derive(TS))]
16#[sqlx(type_name = "verbosity_level", rename_all = "snake_case")]
17#[serde(rename_all = "snake_case")]
18pub enum VerbosityLevel {
19 Low,
20 Medium,
21 High,
22}
23
24#[derive(Clone, PartialEq, Deserialize, Serialize)]
25#[cfg_attr(feature = "ts_rs", derive(TS))]
26pub struct ChatbotConfiguration {
27 pub id: Uuid,
28 pub created_at: DateTime<Utc>,
29 pub updated_at: DateTime<Utc>,
30 pub deleted_at: Option<DateTime<Utc>>,
31 pub course_id: Uuid,
32 pub enabled_to_students: bool,
33 pub chatbot_name: String,
34 pub model_id: Uuid,
35 pub thinking_model: bool,
36 pub prompt: String,
37 pub initial_message: String,
38 pub weekly_tokens_per_user: i32,
39 pub daily_tokens_per_user: i32,
40 pub response_max_tokens: i32,
41 pub temperature: f32,
42 pub top_p: f32,
43 pub frequency_penalty: f32,
44 pub presence_penalty: f32,
45 pub max_completion_tokens: i32,
46 pub verbosity: VerbosityLevel,
47 pub reasoning_effort: ReasoningEffortLevel,
48 pub use_azure_search: bool,
49 pub maintain_azure_search_index: bool,
50 pub hide_citations: bool,
51 pub use_semantic_reranking: bool,
52 pub default_chatbot: bool,
53}
54
55impl Default for ChatbotConfiguration {
56 fn default() -> Self {
57 Self {
58 id: Uuid::nil(),
59 created_at: Default::default(),
60 updated_at: Default::default(),
61 deleted_at: None,
62 course_id: Default::default(),
63 enabled_to_students: false,
64 chatbot_name: Default::default(),
65 model_id: Uuid::nil(),
66 thinking_model: false,
67 prompt: Default::default(),
68 initial_message: Default::default(),
69 weekly_tokens_per_user: 20000 * 5,
70 daily_tokens_per_user: 20000,
71 response_max_tokens: 500,
72 temperature: 0.7,
73 top_p: 1.0,
74 frequency_penalty: 0.0,
75 presence_penalty: 0.0,
76 max_completion_tokens: 600,
77 reasoning_effort: ReasoningEffortLevel::Minimal,
78 verbosity: VerbosityLevel::Medium,
79 use_azure_search: false,
80 maintain_azure_search_index: false,
81 hide_citations: false,
82 use_semantic_reranking: false,
83 default_chatbot: false,
84 }
85 }
86}
87
88#[derive(Clone, PartialEq, Deserialize, Serialize, Debug)]
89#[cfg_attr(feature = "ts_rs", derive(TS))]
90pub struct NewChatbotConf {
91 pub course_id: Uuid,
92 pub enabled_to_students: bool,
93 pub chatbot_name: String,
94 pub model_id: Uuid,
95 pub thinking_model: bool,
96 pub prompt: String,
97 pub initial_message: String,
98 pub weekly_tokens_per_user: i32,
99 pub daily_tokens_per_user: i32,
100 pub response_max_tokens: i32,
101 pub temperature: f32,
102 pub top_p: f32,
103 pub frequency_penalty: f32,
104 pub presence_penalty: f32,
105 pub max_completion_tokens: i32,
106 pub verbosity: VerbosityLevel,
107 pub reasoning_effort: ReasoningEffortLevel,
108 pub use_azure_search: bool,
109 pub maintain_azure_search_index: bool,
110 pub hide_citations: bool,
111 pub use_semantic_reranking: bool,
112 pub default_chatbot: bool,
113 pub chatbotconf_id: Option<Uuid>,
114}
115
116impl Default for NewChatbotConf {
117 fn default() -> Self {
118 let chatbot_conf: ChatbotConfiguration = ChatbotConfiguration::default();
119 Self {
120 course_id: chatbot_conf.course_id,
121 enabled_to_students: chatbot_conf.enabled_to_students,
122 chatbot_name: chatbot_conf.chatbot_name,
123 model_id: chatbot_conf.model_id,
124 thinking_model: chatbot_conf.thinking_model,
125 prompt: chatbot_conf.prompt,
126 initial_message: chatbot_conf.initial_message,
127 weekly_tokens_per_user: chatbot_conf.weekly_tokens_per_user,
128 daily_tokens_per_user: chatbot_conf.daily_tokens_per_user,
129 response_max_tokens: chatbot_conf.response_max_tokens,
130 temperature: chatbot_conf.temperature,
131 top_p: chatbot_conf.top_p,
132 frequency_penalty: chatbot_conf.frequency_penalty,
133 presence_penalty: chatbot_conf.presence_penalty,
134 max_completion_tokens: chatbot_conf.max_completion_tokens,
135 verbosity: chatbot_conf.verbosity,
136 reasoning_effort: chatbot_conf.reasoning_effort,
137 use_azure_search: chatbot_conf.use_azure_search,
138 maintain_azure_search_index: chatbot_conf.maintain_azure_search_index,
139 hide_citations: chatbot_conf.hide_citations,
140 use_semantic_reranking: chatbot_conf.use_semantic_reranking,
141 default_chatbot: chatbot_conf.default_chatbot,
142 chatbotconf_id: None,
143 }
144 }
145}
146
147pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<ChatbotConfiguration> {
148 let res = sqlx::query_as!(
149 ChatbotConfiguration,
150 r#"
151SELECT
152 id,
153 created_at,
154 updated_at,
155 deleted_at,
156 course_id,
157 enabled_to_students,
158 chatbot_name,
159 model_id,
160 thinking_model,
161 prompt,
162 initial_message,
163 weekly_tokens_per_user,
164 daily_tokens_per_user,
165 temperature,
166 top_p,
167 frequency_penalty,
168 presence_penalty,
169 response_max_tokens,
170 max_completion_tokens,
171 use_azure_search,
172 maintain_azure_search_index,
173 hide_citations,
174 use_semantic_reranking,
175 default_chatbot,
176 verbosity as "verbosity: VerbosityLevel",
177 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
178FROM chatbot_configurations
179WHERE id = $1
180AND deleted_at IS NULL
181 "#,
182 id
183 )
184 .fetch_one(conn)
185 .await?;
186 Ok(res)
187}
188
189pub async fn insert(
190 conn: &mut PgConnection,
191 pkey_policy: PKeyPolicy<Uuid>,
192 input: NewChatbotConf,
193) -> ModelResult<ChatbotConfiguration> {
194 let maintain_azure_search_index = input.use_azure_search;
195 let res = sqlx::query_as!(
196 ChatbotConfiguration,
197 r#"
198INSERT INTO chatbot_configurations (
199 id,
200 course_id,
201 enabled_to_students,
202 chatbot_name,
203 model_id,
204 thinking_model,
205 prompt,
206 initial_message,
207 weekly_tokens_per_user,
208 daily_tokens_per_user,
209 temperature,
210 top_p,
211 hide_citations,
212 frequency_penalty,
213 presence_penalty,
214 max_completion_tokens,
215 verbosity,
216 reasoning_effort,
217 response_max_tokens,
218 use_azure_search,
219 maintain_azure_search_index,
220 default_chatbot
221 )
222VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)
223RETURNING
224 id,
225 created_at,
226 updated_at,
227 deleted_at,
228 course_id,
229 enabled_to_students,
230 chatbot_name,
231 model_id,
232 thinking_model,
233 prompt,
234 initial_message,
235 weekly_tokens_per_user,
236 daily_tokens_per_user,
237 temperature,
238 top_p,
239 frequency_penalty,
240 presence_penalty,
241 response_max_tokens,
242 max_completion_tokens,
243 use_azure_search,
244 maintain_azure_search_index,
245 hide_citations,
246 use_semantic_reranking,
247 default_chatbot,
248 verbosity as "verbosity: VerbosityLevel",
249 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
250 "#,
251 pkey_policy.into_uuid(),
252 input.course_id,
253 input.enabled_to_students,
254 input.chatbot_name,
255 input.model_id,
256 input.thinking_model,
257 input.prompt,
258 input.initial_message,
259 input.weekly_tokens_per_user,
260 input.daily_tokens_per_user,
261 input.temperature,
262 input.top_p,
263 input.hide_citations,
264 input.frequency_penalty,
265 input.presence_penalty,
266 input.max_completion_tokens,
267 input.verbosity as VerbosityLevel,
268 input.reasoning_effort as ReasoningEffortLevel,
269 input.response_max_tokens,
270 input.use_azure_search,
271 maintain_azure_search_index,
272 input.default_chatbot
273 )
274 .fetch_one(conn)
275 .await?;
276 Ok(res)
277}
278
279pub async fn edit(
280 conn: &mut PgConnection,
281 input: NewChatbotConf,
282 chatbot_configuration_id: Uuid,
283) -> ModelResult<ChatbotConfiguration> {
284 let res = sqlx::query_as!(
285 ChatbotConfiguration,
286 r#"
287UPDATE chatbot_configurations
288SET
289 enabled_to_students = $1,
290 chatbot_name = $2,
291 prompt = $3,
292 initial_message = $4,
293 weekly_tokens_per_user = $5,
294 daily_tokens_per_user = $6,
295 temperature = $7,
296 top_p = $8,
297 frequency_penalty = $9,
298 presence_penalty = $10,
299 response_max_tokens = $11,
300 use_azure_search = $12,
301 maintain_azure_search_index = $13,
302 hide_citations = $14,
303 use_semantic_reranking = $15,
304 default_chatbot = $16,
305 model_id = $17,
306 thinking_model = $18,
307 max_completion_tokens = $19,
308 verbosity = $20,
309 reasoning_effort = $21
310WHERE id = $22
311RETURNING
312 id,
313 created_at,
314 updated_at,
315 deleted_at,
316 course_id,
317 enabled_to_students,
318 chatbot_name,
319 model_id,
320 thinking_model,
321 prompt,
322 initial_message,
323 weekly_tokens_per_user,
324 daily_tokens_per_user,
325 temperature,
326 top_p,
327 frequency_penalty,
328 presence_penalty,
329 response_max_tokens,
330 max_completion_tokens,
331 use_azure_search,
332 maintain_azure_search_index,
333 hide_citations,
334 use_semantic_reranking,
335 default_chatbot,
336 verbosity as "verbosity: VerbosityLevel",
337 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
338"#,
339 input.enabled_to_students,
340 input.chatbot_name,
341 input.prompt,
342 input.initial_message,
343 input.weekly_tokens_per_user,
344 input.daily_tokens_per_user,
345 input.temperature,
346 input.top_p,
347 input.frequency_penalty,
348 input.presence_penalty,
349 input.response_max_tokens,
350 input.use_azure_search,
351 input.maintain_azure_search_index,
352 input.hide_citations,
353 input.use_semantic_reranking,
354 input.default_chatbot,
355 input.model_id,
356 input.thinking_model,
357 input.max_completion_tokens,
358 input.verbosity as VerbosityLevel,
359 input.reasoning_effort as ReasoningEffortLevel,
360 chatbot_configuration_id
361 )
362 .fetch_one(conn)
363 .await?;
364 Ok(res)
365}
366
367pub async fn delete(conn: &mut PgConnection, chatbot_configuration_id: Uuid) -> ModelResult<()> {
368 sqlx::query!(
369 r#"
370UPDATE chatbot_configurations
371SET deleted_at = now()
372WHERE id = $1
373AND deleted_at IS NULL
374 "#,
375 chatbot_configuration_id
376 )
377 .execute(conn)
378 .await?;
379 Ok(())
380}
381
382pub async fn get_for_course(
383 conn: &mut PgConnection,
384 course_id: Uuid,
385) -> ModelResult<Vec<ChatbotConfiguration>> {
386 let res = sqlx::query_as!(
387 ChatbotConfiguration,
388 r#"
389SELECT
390 id,
391 created_at,
392 updated_at,
393 deleted_at,
394 course_id,
395 enabled_to_students,
396 chatbot_name,
397 model_id,
398 thinking_model,
399 prompt,
400 initial_message,
401 weekly_tokens_per_user,
402 daily_tokens_per_user,
403 temperature,
404 top_p,
405 frequency_penalty,
406 presence_penalty,
407 response_max_tokens,
408 max_completion_tokens,
409 use_azure_search,
410 maintain_azure_search_index,
411 hide_citations,
412 use_semantic_reranking,
413 default_chatbot,
414 verbosity as "verbosity: VerbosityLevel",
415 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
416FROM chatbot_configurations
417WHERE course_id = $1
418AND deleted_at IS NULL
419"#,
420 course_id
421 )
422 .fetch_all(conn)
423 .await?;
424 Ok(res)
425}
426
427pub async fn get_enabled_nondefault_for_course(
428 conn: &mut PgConnection,
429 course_id: Uuid,
430) -> ModelResult<Vec<ChatbotConfiguration>> {
431 let res = sqlx::query_as!(
432 ChatbotConfiguration,
433 r#"
434SELECT
435 id,
436 created_at,
437 updated_at,
438 deleted_at,
439 course_id,
440 enabled_to_students,
441 chatbot_name,
442 model_id,
443 thinking_model,
444 prompt,
445 initial_message,
446 weekly_tokens_per_user,
447 daily_tokens_per_user,
448 temperature,
449 top_p,
450 frequency_penalty,
451 presence_penalty,
452 response_max_tokens,
453 max_completion_tokens,
454 use_azure_search,
455 maintain_azure_search_index,
456 hide_citations,
457 use_semantic_reranking,
458 default_chatbot,
459 verbosity as "verbosity: VerbosityLevel",
460 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
461FROM chatbot_configurations
462WHERE course_id = $1
463AND default_chatbot IS false
464AND enabled_to_students IS true
465AND deleted_at IS NULL
466"#,
467 course_id
468 )
469 .fetch_all(conn)
470 .await?;
471 Ok(res)
472}
473
474pub async fn get_for_azure_search_maintenance(
475 conn: &mut PgConnection,
476) -> ModelResult<Vec<ChatbotConfiguration>> {
477 let res = sqlx::query_as!(
478 ChatbotConfiguration,
479 r#"
480SELECT
481 id,
482 created_at,
483 updated_at,
484 deleted_at,
485 course_id,
486 enabled_to_students,
487 chatbot_name,
488 model_id,
489 thinking_model,
490 prompt,
491 initial_message,
492 weekly_tokens_per_user,
493 daily_tokens_per_user,
494 temperature,
495 top_p,
496 frequency_penalty,
497 presence_penalty,
498 response_max_tokens,
499 max_completion_tokens,
500 use_azure_search,
501 maintain_azure_search_index,
502 hide_citations,
503 use_semantic_reranking,
504 default_chatbot,
505 verbosity as "verbosity: VerbosityLevel",
506 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
507
508FROM chatbot_configurations
509WHERE maintain_azure_search_index = true
510AND deleted_at IS NULL
511"#,
512 )
513 .fetch_all(conn)
514 .await?;
515 Ok(res)
516}
517
518pub async fn remove_default_chatbot_from_course(
519 conn: &mut PgConnection,
520 course_id: Uuid,
521) -> ModelResult<()> {
522 sqlx::query!(
523 r#"
524UPDATE chatbot_configurations
525SET default_chatbot = false
526WHERE course_id = $1
527AND default_chatbot = true
528AND deleted_at IS NULL
529"#,
530 course_id,
531 )
532 .execute(conn)
533 .await?;
534 Ok(())
535}
536
537pub async fn set_default_chatbot_for_course(
538 conn: &mut PgConnection,
539 chatbot_configuration_id: Uuid,
540) -> ModelResult<ChatbotConfiguration> {
541 let res = sqlx::query_as!(
542 ChatbotConfiguration,
543 r#"
544UPDATE chatbot_configurations
545SET default_chatbot = true
546WHERE id = $1
547RETURNING
548 id,
549 created_at,
550 updated_at,
551 deleted_at,
552 course_id,
553 enabled_to_students,
554 chatbot_name,
555 model_id,
556 thinking_model,
557 prompt,
558 initial_message,
559 weekly_tokens_per_user,
560 daily_tokens_per_user,
561 temperature,
562 top_p,
563 frequency_penalty,
564 presence_penalty,
565 response_max_tokens,
566 max_completion_tokens,
567 use_azure_search,
568 maintain_azure_search_index,
569 hide_citations,
570 use_semantic_reranking,
571 default_chatbot,
572 verbosity as "verbosity: VerbosityLevel",
573 reasoning_effort as "reasoning_effort: ReasoningEffortLevel"
574"#,
575 chatbot_configuration_id,
576 )
577 .fetch_one(conn)
578 .await?;
579 Ok(res)
580}