diff --git a/src/action.rs b/src/action.rs index c6d6517..2e5eaa6 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,4 +1,4 @@ -use crate::app::types::{ChatTransaction, Model}; +use crate::app::types::{ChatResponse, Model, Transaction}; use serde::{ de::{self, Deserializer, Visitor}, Deserialize, Serialize, @@ -18,7 +18,7 @@ pub enum Action { Help, SubmitInput(String), SelectModel(Model), - ProcessResponse(Box), + ProcessResponse(Box), EnterNormal, EnterInsert, EnterProcessing, diff --git a/src/app/errors.rs b/src/app/errors.rs index b934897..74fcacc 100644 --- a/src/app/errors.rs +++ b/src/app/errors.rs @@ -1,6 +1,17 @@ use async_openai::error::OpenAIError; use std::fmt; +#[derive(Debug)] +pub enum SazidError { + OpenAiError(OpenAIError), +} +impl fmt::Display for SazidError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SazidError::OpenAiError(err) => write!(f, "OpenAIError: {}", err), + } + } +} #[derive(Debug)] pub enum ChunkifierError { IO(std::io::Error), diff --git a/src/app/types.rs b/src/app/types.rs index 949d967..615527c 100644 --- a/src/app/types.rs +++ b/src/app/types.rs @@ -2,16 +2,238 @@ use crate::{app::consts::*, trace_dbg}; use ansi_to_tui::IntoText; use async_openai::{ self, + config::OpenAIConfig, + error::OpenAIError, types::{ ChatChoice, ChatCompletionRequestMessage, ChatCompletionResponseStreamMessage, CreateChatCompletionRequest, CreateChatCompletionResponse, CreateChatCompletionStreamResponse, FunctionCall, FunctionCallStream, Role, }, + Client, }; use clap::Parser; use nu_ansi_term::Color; use ratatui::text::Text; use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, ffi::OsString, path::PathBuf}; +use std::{ + collections::{BTreeMap, HashMap}, + ffi::OsString, + path::PathBuf, +}; +use uuid::Uuid; + +use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub enum ChatResponse { + Response(CreateChatCompletionResponse), + StreamResponse(CreateChatCompletionStreamResponse), +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct RenderedFunctionCall { + pub name: String, + pub arguments: String, +} + +impl From for RenderedFunctionCall { + fn from(function_call: FunctionCallStream) -> Self { + RenderedFunctionCall { + name: function_call.name.unwrap_or("".to_string()), + arguments: function_call.arguments.unwrap_or("".to_string()), + } + } +} + +impl From for RenderedFunctionCall { + fn from(function_call: FunctionCall) -> Self { + RenderedFunctionCall { name: function_call.name, arguments: function_call.arguments } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)] +pub struct RenderedChatMessage { + pub role: Option, + pub content: Option, + pub function_call: Option, + pub finish_reason: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Transaction { + pub id: Option, + pub request: CreateChatCompletionRequest, + pub responses: Vec, + pub rendered: Vec, + pub completed: bool, + pub styled: bool, +} + +use futures::StreamExt; + +impl Transaction { + pub fn new(request: CreateChatCompletionRequest) -> Self { + Transaction { id: None, request, responses: Vec::new(), rendered: Vec::new(), completed: false, styled: false } + } + + pub fn new_request( + &self, + response_callback: R, + complete_callback: C, + error_callback: E, + client: async_openai::Client, + stream_response: bool, + ) where + R: Fn(ChatResponse) + Send + 'static, + C: Fn() + Send + 'static, + E: Fn(String) + Send + 'static, + { + let request = self.request.clone(); + tokio::spawn(async move { + match stream_response { + true => { + // let mut stream: Pin> + Send>> = + let mut stream = client.chat().create_stream(request).await.unwrap(); + while let Some(response_result) = stream.next().await { + match response_result { + Ok(response) => { + trace_dbg!("Response: {:#?}", response); + response_callback(ChatResponse::StreamResponse(response)); + }, + Err(e) => { + trace_dbg!("Error: {:#?} -- check https://status.openai.com/", e); + error_callback(format!("Error: {:#?} -- check https://status.openai.com/", e)); + }, + } + } + }, + false => match client.chat().create(request).await { + Ok(response) => { + response_callback(ChatResponse::Response(response)); + }, + Err(e) => { + trace_dbg!("Error: {}", e); + error_callback(format!("Error: {:#?} -- check https://status.openai.com/", e)); + }, + }, + }; + complete_callback(); + }); + } + + pub fn render(&mut self) { + if !self.completed { + self.rendered.push(::from(self.request.clone())); + + let choice_count = self + .responses + .iter() + .map(|r| match r { + ChatResponse::Response(response) => response.choices.len(), + ChatResponse::StreamResponse(response) => response.choices.len(), + }) + .max() + .unwrap(); + self.rendered = vec![RenderedChatMessage::default(); choice_count]; + for (index, rendered_message) in self.rendered.iter_mut().enumerate() { + for response in self.responses.clone() { + match response { + ChatResponse::Response(response) => { + rendered_message.content = response.choices[index].message.content.clone(); + if let Some(function_call) = response.choices[index].message.function_call.clone() { + rendered_message.function_call = Some(function_call.into()) + } + }, + ChatResponse::StreamResponse(response) => { + rendered_message.content = response.choices[index].delta.content.clone(); + if let Some(function_call) = response.choices[index].delta.function_call.clone() { + match rendered_message.function_call { + Some(ref mut rendered_function_call) => { + rendered_function_call.name += function_call.name.unwrap_or("".to_string()).as_str(); + rendered_function_call.arguments += function_call.arguments.unwrap_or("".to_string()).as_str(); + }, + None => rendered_message.function_call = Some(function_call.into()), + } + } + }, + } + } + } + } + } +} + +impl From<&Transaction> for String { + fn from(txn: &Transaction) -> Self { + txn + .rendered + .iter() + .map(|m| { + let mut string_vec: Vec = Vec::new(); + if let Some(content) = m.content.clone() { + string_vec.push(content); + } + if let Some(function_call) = m.function_call.clone() { + string_vec.push(format!( + "function call: {} {}", + function_call.name.as_str(), + function_call.arguments.as_str() + )); + } + string_vec.join("\n") + }) + .collect::>() + .join("\n") + } +} + +impl From for String { + fn from(message: RenderedChatMessage) -> Self { + let mut string_vec: Vec = Vec::new(); + if let Some(content) = message.content { + string_vec.push(content); + } + if let Some(function_call) = message.function_call { + string_vec.push(format!("function call: {} {}", function_call.name.as_str(), function_call.arguments.as_str())); + } + string_vec.join("\n") + } +} + +impl From for RenderedChatMessage { + fn from(request: CreateChatCompletionRequest) -> Self { + RenderedChatMessage { + role: Some(request.messages.last().unwrap().role.clone()), + content: Some(request.messages.last().unwrap().content.clone().unwrap_or("".to_string())), + function_call: Some(::from( + request.messages.last().unwrap().function_call.clone().unwrap(), + )), + finish_reason: None, + } + } +} +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- +// -------------------------------------- + +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- +// --------------------------------------------------- // options #[derive(Parser, Clone, Default, Debug)] @@ -75,227 +297,6 @@ impl GPTSettings { } } -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Transaction { - pub txn_id: String, - pub originals: Vec, - pub rendered: Option>, - pub completed: bool, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub enum ChatTransaction { - Request(CreateChatCompletionRequest), - Response(CreateChatCompletionResponse), - StreamResponse(CreateChatCompletionStreamResponse), -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub enum ChatMessage { - Request(ChatCompletionRequestMessage), - Response(ChatChoice), - StreamResponse(ChatCompletionResponseStreamMessage), -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct RenderedFunctionCall { - pub name: Option, - pub arguments: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -pub struct RenderedChatMessage { - pub role: Option, - pub content: Option, - pub function_call: Option, - pub finish_reason: Option, -} - -#[derive(Default, Serialize, Deserialize, Debug, Clone)] -pub struct RenderedChatTransaction { - pub id: Option, - pub choices: Vec, -} - -impl<'a> From for Text<'a> { - fn from(transaction: ChatTransaction) -> Self { - let string = ::from(transaction); - string.bytes().collect::>().into_text().unwrap() - } -} -impl ChatTransaction { - pub fn get_rendered_chat_messages(&self) { - match self { - ChatTransaction::StreamResponse(sr) => {}, - ChatTransaction::Response(response) => {}, - ChatTransaction::Request(request) => {}, - } - } -} - -impl From for Vec { - fn from(transaction: ChatTransaction) -> Self { - match transaction { - ChatTransaction::Request(request) => vec![request - .messages - .iter() - .map(|message| RenderedChatMessage::from(ChatMessage::Request(message.clone()))) - .last() - .unwrap()], - ChatTransaction::Response(response) => { - response.choices.iter().map(|choice| RenderedChatMessage::from(ChatMessage::Response(choice.clone()))).collect() - }, - ChatTransaction::StreamResponse(response_stream) => response_stream - .choices - .iter() - .map(|choice| RenderedChatMessage::from(ChatMessage::StreamResponse(choice.clone()))) - .collect(), - } - } -} - -impl From for Option { - fn from(transaction: ChatTransaction) -> Self { - match transaction { - ChatTransaction::Request(request) => Some(request), - _ => None, - } - } -} - -impl From for Option { - fn from(transaction: ChatTransaction) -> Self { - match transaction { - ChatTransaction::Response(response) => Some(response), - _ => None, - } - } -} - -impl From for Option { - fn from(transaction: ChatTransaction) -> Self { - match transaction { - ChatTransaction::StreamResponse(response) => Some(response), - _ => None, - } - } -} - -use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input}; - -impl From for String { - fn from(transaction: ChatTransaction) -> Self { - let get_content = |messages: Vec| { - messages - .iter() - .map(|message| message.content.clone().unwrap().to_string()) - .collect::>() - .join("") - .lines() - .map(|line| line.to_string()) - .collect::>() - .join("\n") - }; - - let consolidate_stream_fragments = |messages: Vec| { - let mut consolidated_messages: Vec = Vec::new(); - let mut consolidated_message = RenderedChatMessage::default(); - let mut consolidated_function_call_names: Vec> = Vec::new(); - let mut consolidated_function_call_arguments: Vec> = Vec::new(); - let mut it = messages.iter().peekable(); - while let Some(message) = it.next() { - if message.role.is_some() { - consolidated_message.role = message.role.clone(); - } - if message.function_call.is_some() { - consolidated_function_call_names.push(message.function_call.as_ref().unwrap().name.clone()); - consolidated_function_call_arguments.push(message.function_call.as_ref().unwrap().arguments.clone()); - } - match consolidated_message.content { - Some(_) => { - consolidated_message.content = Some(format!( - "{}{}", - consolidated_message.content.unwrap(), - message.content.clone().unwrap_or("".to_string()) - )) - }, - None => consolidated_message.content = message.content.clone(), - } - if message.finish_reason.is_some() || it.peek().is_none() { - if !consolidated_function_call_names.is_empty() || !consolidated_function_call_arguments.is_empty() { - consolidated_message.function_call = Some(RenderedFunctionCall { - name: Some( - consolidated_function_call_names.clone().into_iter().flatten().collect::>().join(" "), - ), - arguments: Some( - consolidated_function_call_arguments.clone().into_iter().flatten().collect::>().join(" "), - ), - }); - } - consolidated_function_call_arguments = Vec::new(); - consolidated_function_call_names = Vec::new(); - consolidated_message.finish_reason = message.finish_reason.clone(); - consolidated_messages.push(consolidated_message.clone()); - consolidated_message = RenderedChatMessage::default(); - } - } - consolidated_messages - }; - - match transaction { - ChatTransaction::Request(request) => { - let content = get_content(vec![request - .messages - .iter() - .map(|message| RenderedChatMessage::from(ChatMessage::Request(message.clone()))) - .last() - .unwrap()]); - Color::Magenta.paint(content).to_string() - }, - ChatTransaction::Response(response) => { - let content = get_content( - response - .choices - .iter() - .map(|choice| RenderedChatMessage::from(ChatMessage::Response(choice.clone()))) - .collect(), - ); - Color::Cyan.paint(content).to_string() - }, - ChatTransaction::StreamResponse(response_stream) => { - let messages = consolidate_stream_fragments( - response_stream - .choices - .iter() - .map(|choice| RenderedChatMessage::from(ChatMessage::StreamResponse(choice.clone()))) - .collect(), - ); - let config = Config { colored_output: true, language: Some("markdown"), ..Default::default() }; - let assets = HighlightingAssets::from_binary(); - let controller = Controller::new(&config, &assets); - let mut buffer = String::new(); - for message in messages { - let mut text = String::new(); - if let Some(content) = message.content { - text += format!("{}\n", content).as_str() - } - if let Some(function_call) = message.function_call { - text += format!( - "executing function: {} {}\n", - function_call.name.unwrap_or("none".to_string()), - function_call.arguments.unwrap_or("none".to_string()) - ) - .as_str() - } - let input = Input::from_bytes(text.as_bytes()); - controller.run(vec![input.into()], Some(&mut buffer)).unwrap(); - } - buffer - }, - } - } -} - #[derive(Debug, Deserialize, Clone)] pub struct ModelConfig { pub name: String, @@ -324,49 +325,6 @@ pub struct PdfText { pub errors: Vec, } -// impl<'a> From for Vec> { -// fn from(value: RenderedChatMessage) -> Self { -// value.content.lines().map(|line| Span::styled(line.to_string(), value.get_style())).collect() -// } -// } - -impl From for RenderedFunctionCall { - fn from(function_call: FunctionCall) -> Self { - RenderedFunctionCall { name: Some(function_call.name), arguments: Some(function_call.arguments) } - } -} - -impl From for RenderedFunctionCall { - fn from(function_call: FunctionCallStream) -> Self { - RenderedFunctionCall { name: function_call.name, arguments: function_call.arguments } - } -} - -impl From for RenderedChatMessage { - fn from(message: ChatMessage) -> Self { - match message { - ChatMessage::Request(request) => RenderedChatMessage { - role: Some(request.role), - content: request.content, - function_call: request.function_call.map(|function_call| function_call.into()), - finish_reason: None, - }, - ChatMessage::Response(response) => RenderedChatMessage { - role: Some(response.message.role), - content: response.message.content, - function_call: response.message.function_call.map(|function_call| function_call.into()), - finish_reason: response.finish_reason, - }, - ChatMessage::StreamResponse(response_streams) => RenderedChatMessage { - role: response_streams.delta.role, - content: response_streams.delta.content, - function_call: response_streams.delta.function_call.map(|function_call| function_call.into()), - finish_reason: response_streams.finish_reason, - }, - } - } -} - #[derive(Debug, Serialize, Deserialize)] pub struct IngestedData { session_id: String, diff --git a/src/components/session.rs b/src/components/session.rs index ea56530..88f038c 100644 --- a/src/components/session.rs +++ b/src/components/session.rs @@ -179,13 +179,13 @@ impl Component for Session { let _title = "Chat"; - let transaction_texts = concatenate_texts(self.transactions.iter().cloned().map(::from)); - let block = Block::default().borders(Borders::NONE).gray(); // .title(Title::from("left").alignment(Alignment::Left)); //.title(Title::from("right").alignment(Alignment::Right)); - let paragraph = - Paragraph::new(transaction_texts).block(block).wrap(Wrap { trim: true }).scroll((self.vertical_scroll as u16, 0)); + let paragraph = Paragraph::new(Text::<'_>::from(self.get_full_text())) + .block(block) + .wrap(Wrap { trim: true }) + .scroll((self.vertical_scroll as u16, 0)); f.render_widget(paragraph, inner[1]); f.render_stateful_widget( @@ -211,113 +211,22 @@ where } result } + impl Session { pub fn new() -> Session { Self::default() } - pub fn render_transaction_text(&mut self) { - let mut completed_ids: HashMap = HashMap::new(); - let mut rendered_transactions: Vec = Vec::new(); - let mut finish_reason: Option = None; - for transaction in &self.transactions { - for original_transaction in &transaction.originals { - if !completed_ids.contains_key(&transaction.txn_id) { - if let ChatTransaction::StreamResponse(response) = original_transaction { - completed_ids.insert(transaction.txn_id.clone(), true); - - let mut combined_deltas: HashMap = HashMap::new(); - - for message in &response.choices { - let delta = &message.delta; - let key = format!("{:?}{:?}", &delta.role, &delta.function_call); - if let Some(reason) = message.finish_reason.clone() { - finish_reason = Some(reason); - transaction.completed = true; - } - if let Some(existing_delta) = combined_deltas.get_mut(&key) { - if let Some(content) = &delta.content { - existing_delta.content = existing_delta.content.clone().map(|c| c + content); - } - - if let Some(call) = &delta.function_call { - if let Some(existing_call) = &mut existing_delta.function_call { - existing_call.name = existing_call.name.clone().map(|n| n + &call.name.unwrap_or("".to_string())); - existing_call.arguments = - existing_call.arguments.clone().map(|a| a + &call.arguments.unwrap_or("".to_string())); - } else { - existing_delta.function_call = - Some(FunctionCallStream { name: call.name.clone(), arguments: call.arguments.clone() }); - } - } - } else { - combined_deltas.insert(key, delta.clone()); - } - } - - rendered_transactions.push(RenderedChatTransaction { - id: Some(transaction.txn_id.clone()), - choices: combined_deltas - .values() - .map(|delta| RenderedChatMessage { - role: delta.role.clone(), - content: delta.content.clone(), - function_call: delta.function_call.as_ref().map(|func_call| RenderedFunctionCall { - name: func_call.name.clone(), - arguments: func_call.arguments.clone(), - }), - finish_reason, - }) - .collect(), - }); - finish_reason = None; - } - } - } - if let Some(mut rendered_txns) = transaction.rendered { - rendered_txns.append(rendered_transactions.as_mut()); - } else { - transaction.rendered = Some(rendered_transactions) - } - } + fn get_previous_request_messages(&self) -> Vec { + self.transactions.iter().map(|transaction| transaction.request.messages.clone()).flatten().collect() } - - pub fn add_transaction(&self, transaction: ChatTransaction) { - match transaction { - ChatTransaction::Request(request) => { - let txn_id = Uuid::new_v4().to_string(); - let originals = vec![ChatTransaction::Request(request.clone())]; - let txn = Transaction { txn_id, originals, rendered: None, completed: true }; - self.transactions.push(txn); - }, - ChatTransaction::Response(response) => { - let txn_id = response.id; - let originals = vec![ChatTransaction::Response(response.clone())]; - let txn = Transaction { txn_id, originals, rendered: None, completed: false }; - self.transactions.push(txn); - }, - ChatTransaction::StreamResponse(response) => { - let txn_id = response.id; - let originals = vec![ChatTransaction::StreamResponse(response.clone())]; - let txn = Transaction { txn_id, originals, rendered: None, completed: false }; - self.transactions.push(txn); - }, - } + pub fn get_full_text(&mut self) -> String { + self.transactions.iter().map(|transaction| ::from(transaction)).collect::>().join("\n") } - pub fn get_previous_request_messages(&self) -> Vec { - self - .transactions - .clone() - .into_iter() - .filter_map(|t| match t { - ChatTransaction::Request(r) => Some(r.messages.clone()), - _ => None, - }) - .flatten() - .collect() + pub fn response_callback(&self, response: ChatResponse) { + self.action_tx.clone().unwrap().send(Action::ProcessResponse(Box::new(response))).unwrap(); } - pub fn request_response(&mut self, input: String, tx: UnboundedSender) { //let tx = self.action_tx.clone().unwrap(); let previous_requests = self.get_previous_request_messages(); @@ -332,66 +241,23 @@ impl Session { let stream_response = self.config.stream_response; let openai_config = self.config.openai_config.clone(); format!("Request: {:#?}", request.clone()); - self.transactions.push(ChatTransaction::Request(request.clone())); - tx.send(Action::Render).unwrap(); - tokio::spawn(async move { - tx.send(Action::EnterProcessing).unwrap(); - let client = create_openai_client(openai_config); - match stream_response { - true => { - let mut stream = client.chat().create_stream(request).await.unwrap(); - while let Some(response_result) = stream.next().await { - match response_result { - Ok(response) => { - trace_dbg!("Response: {:#?}", response); - tx.send(Action::ProcessResponse(Box::new(ChatTransaction::StreamResponse(response)))).unwrap(); - }, - Err(e) => { - trace_dbg!("Error: {:#?} -- check https://status.openai.com/", e); - tx.send(Action::Error(format!("Error: {}", e))).unwrap(); - }, - } - } - }, - false => match client.chat().create(request).await { - Ok(response) => { - tx.send(Action::ProcessResponse(Box::new(ChatTransaction::Response(response)))).unwrap(); - }, - Err(e) => { - trace_dbg!("Error: {}", e); - tx.send(Action::Error(format!("Error: {}", e))).unwrap(); - }, - }, - }; - }); - } - pub fn consolidate_stream_responses_by_id(&self) { - // if let ChatTransaction::StreamResponse(mut new_sr) = transaction { - // while let Some(choice) = new_sr.choices.pop() { - // //let choice = new_sr.choices[0].clone(); - // saved_sr.choices.push(choice); - // } - // if saved_sr.choices.last().unwrap().finish_reason.is_some() { - // tx.send(Action::ExitProcessing).unwrap(); - // } - // } + tx.send(Action::EnterProcessing).unwrap(); + let client = create_openai_client(openai_config); + //let response_callback = |response| tx.send(Action::ProcessResponse(Box::new(response))).unwrap(); + let complete_callback = || tx.send(Action::ExitProcessing).unwrap(); + let error_callback = |e| tx.send(Action::Error(e)).unwrap(); + self.transactions.push(Transaction::new(request)); + self.transactions.last().unwrap().new_request::<_, _, _>( + response_callback, + complete_callback, + error_callback, + client, + stream_response, + ); } - pub fn process_response_handler(&mut self, tx: UnboundedSender, transaction: ChatTransaction) { - self.add_transaction(transaction); - // if let Some(ChatTransaction::StreamResponse(saved_sr)) = self.transactions.last_mut() { - // if let ChatTransaction::StreamResponse(mut new_sr) = transaction { - // while let Some(choice) = new_sr.choices.pop() { - // //let choice = new_sr.choices[0].clone(); - // saved_sr.choices.push(choice); - // } - // if saved_sr.choices.last().unwrap().finish_reason.is_some() { - // tx.send(Action::ExitProcessing).unwrap(); - // } - // } - // } else { - // self.transactions.push(transaction); - // } + + pub fn process_response_handler(&mut self, tx: UnboundedSender, response: ChatResponse) { trace_dbg!("response handler"); tx.send(Action::Update).unwrap(); } diff --git a/temp.rs b/temp.rs index a15ace6..8b57c0c 100644 --- a/temp.rs +++ b/temp.rs @@ -10,6 +10,21 @@ // The resulting RenderedChatTransaction should be added to self.rendered_transactions // use the following code to help you understand the data structures // do not abbreviate and do not use code stubs such as // handle this here and // do this here +// the originals + +#[derive(Default, Serialize, Deserialize, Debug, Clone)] +pub struct Session { + pub transactions: Vec, +} + +#[derive(Clone, Default)] +pub struct RenderedChatTransaction { + pub id: Option, + pub original_transactions: Vec, + pub choices: Option>, + pub rendered: bool, + pub styled: bool, +} pub struct Transaction { pub id: String, @@ -69,16 +84,6 @@ pub enum ChatTransaction { Response(CreateChatCompletionResponse), StreamResponse(CreateChatCompletionStreamResponse), } -#[derive(Clone, Default)] -pub struct RenderedChatTransaction { - pub id: Option, - pub choices: Vec, -} - -#[derive(Default, Serialize, Deserialize, Debug, Clone)] -pub struct Session { - pub transactions: Vec, -} #[derive(Clone, Default)] pub struct RenderedChatMessage {