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