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