headless_lms_models/
chatbot_conversations.rs1use futures::future::OptionFuture;
2use utoipa::ToSchema;
3
4use crate::{
5 chatbot_conversation_messages::ChatbotConversationMessage,
6 chatbot_conversation_messages_citations::ChatbotConversationMessageCitation,
7 chatbot_conversation_suggested_messages::ChatbotConversationSuggestedMessage, prelude::*,
8};
9
10#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
11
12pub struct ChatbotConversation {
13 pub id: Uuid,
14 pub created_at: DateTime<Utc>,
15 pub updated_at: DateTime<Utc>,
16 pub deleted_at: Option<DateTime<Utc>>,
17 pub course_id: Uuid,
18 pub user_id: Uuid,
19 pub chatbot_configuration_id: Uuid,
20}
21
22#[derive(Serialize, Deserialize, PartialEq, Clone, ToSchema)]
23
24pub struct ChatbotConversationInfo {
26 pub current_conversation: Option<ChatbotConversation>,
27 pub current_conversation_messages: Option<Vec<ChatbotConversationMessage>>,
28 pub current_conversation_message_citations: Option<Vec<ChatbotConversationMessageCitation>>,
29 pub chatbot_name: String,
30 pub course_name: String,
31 pub hide_citations: bool,
32 pub suggested_messages: Option<Vec<ChatbotConversationSuggestedMessage>>,
33}
34
35pub async fn insert(
36 conn: &mut PgConnection,
37 input: ChatbotConversation,
38) -> ModelResult<ChatbotConversation> {
39 let res = sqlx::query_as!(
40 ChatbotConversation,
41 r#"
42INSERT INTO chatbot_conversations (course_id, user_id, chatbot_configuration_id)
43VALUES ($1, $2, $3)
44RETURNING *
45 "#,
46 input.course_id,
47 input.user_id,
48 input.chatbot_configuration_id
49 )
50 .fetch_one(conn)
51 .await?;
52 Ok(res)
53}
54
55pub async fn get_latest_conversation_for_user(
56 conn: &mut PgConnection,
57 user_id: Uuid,
58 chatbot_configuration_id: Uuid,
59) -> ModelResult<ChatbotConversation> {
60 let res = sqlx::query_as!(
61 ChatbotConversation,
62 r#"
63SELECT *
64FROM chatbot_conversations
65WHERE user_id = $1
66 AND chatbot_configuration_id = $2
67 AND deleted_at IS NULL
68ORDER BY created_at DESC
69LIMIT 1
70 "#,
71 user_id,
72 chatbot_configuration_id
73 )
74 .fetch_one(conn)
75 .await?;
76 Ok(res)
77}
78
79pub async fn get_current_conversation_info(
81 tx: &mut PgConnection,
82 user_id: Uuid,
83 chatbot_configuration_id: Uuid,
84) -> ModelResult<ChatbotConversationInfo> {
85 let chatbot_configuration =
86 crate::chatbot_configurations::get_by_id(tx, chatbot_configuration_id).await?;
87 let course = crate::courses::get_course(tx, chatbot_configuration.course_id).await?;
88 let current_conversation =
89 get_latest_conversation_for_user(tx, user_id, chatbot_configuration_id)
90 .await
91 .optional()?;
92 let current_conversation_messages = OptionFuture::from(
94 current_conversation
95 .clone()
96 .map(|c| crate::chatbot_conversation_messages::get_by_conversation_id(tx, c.id)),
97 )
98 .await
99 .transpose()?;
100
101 let current_conversation_message_citations =
102 OptionFuture::from(current_conversation.clone().map(|c| {
103 crate::chatbot_conversation_messages_citations::get_by_conversation_id(tx, c.id)
104 }))
105 .await
106 .transpose()?;
107
108 let suggested_messages = if chatbot_configuration.suggest_next_messages
109 && let Some(ccm) = ¤t_conversation_messages
110 && let Some(last_ccm) = ccm.last()
111 {
112 let sm = crate::chatbot_conversation_suggested_messages::get_by_conversation_message_id(
113 tx,
114 last_ccm.id.to_owned(),
115 )
116 .await?;
117 Some(sm)
119 } else {
120 None
121 };
122
123 Ok(ChatbotConversationInfo {
124 current_conversation,
125 current_conversation_messages,
126 current_conversation_message_citations,
127 suggested_messages,
128 chatbot_name: chatbot_configuration.chatbot_name,
130 course_name: course.name,
131 hide_citations: chatbot_configuration.hide_citations,
132 })
133}