headless_lms_models/
chatbot_configurations.rs

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}