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