next_web_ai/chat/client/
default_chat_client.rs1use bytes::Bytes;
2use next_web_core::async_trait;
3use serde::de::DeserializeOwned;
4
5use crate::{
6 chat::{
7 client::{
8 advisor::api::advisor::Advisor,
9 chat_client::{
10 CallResponseSpec, ChatClient, ChatClientRequestSpec, StreamResponseSpec,
11 },
12 response_entity::ResponseEntity,
13 },
14 messages::message::Message,
15 model::{chat_model::ChatModel, chat_response::ChatResponse},
16 prompt::{chat_options::ChatOptions, prompt::Prompt},
17 },
18 convert::converter::{Converter, StructuredOutputConverter},
19 model::model_request::ModelRequest,
20};
21
22pub struct DefaultChatClient {
23 pub(crate) default_chat_client_request: DefaultChatClientRequestSpec,
24}
25
26impl ChatClient for DefaultChatClient {
27 fn prompt(&self, prompt: Prompt) -> impl super::chat_client::ChatClientRequestSpec {
28 let mut spec = self.default_chat_client_request.clone();
29
30 spec.chat_options = prompt.chat_options().to_owned();
32
33 if !prompt.instructions().is_empty() {
35 spec.messages = prompt.instructions();
36 }
37
38 spec
39 }
40
41 fn prompt_from_content<T>(&self, message: T) -> impl super::chat_client::ChatClientRequestSpec
42 where
43 T: Into<bytes::Bytes>,
44 {
45 let message = message.into();
46 assert!(message.len() > 0);
47 self.prompt(Prompt::from_contents(
48 message,
49 self.default_chat_client_request.chat_options.clone(),
50 ))
51 }
52
53 fn prompt_from_default(&self) -> impl super::chat_client::ChatClientRequestSpec {
54 self.default_chat_client_request.clone()
55 }
56}
57
58#[derive(Clone)]
59pub struct DefaultChatClientRequestSpec {
60 pub(crate) chat_model: Box<dyn ChatModel>,
61 pub(crate) messages: Vec<Box<dyn Message>>,
62 pub(crate) advisors: Vec<Box<dyn Advisor>>,
63
64 pub(crate) user_text: Bytes,
65 pub(crate) system_text: Bytes,
66 pub(crate) chat_options: Box<dyn ChatOptions>,
67}
68
69#[async_trait]
70impl ChatClientRequestSpec for DefaultChatClientRequestSpec {
71 async fn call(&self) -> impl CallResponseSpec {
72 DefaultCallResponseSpec {
73 request: self.clone(),
74 }
75 }
76
77 async fn stream(&self) -> impl StreamResponseSpec {
78 DefaultStreamResponseSpec {
79 request: self.clone(),
80 }
81 }
82
83 fn user<T>(&mut self, text: T)
84 where
85 T: Into<Bytes>,
86 {
87 let text = text.into();
88 assert!(text.len() > 0);
89 self.user_text = text;
90 }
91
92 fn system<T>(&mut self, text: T)
93 where
94 T: Into<Bytes>,
95 {
96 let text = text.into();
97 assert!(text.len() > 0);
98 self.system_text = text;
99 }
100}
101
102pub struct DefaultCallResponseSpec {
103 pub(crate) request: DefaultChatClientRequestSpec,
104}
105
106impl DefaultCallResponseSpec {
107 fn do_response_entity<T, C>(&self, output_converter: C) -> ResponseEntity<ChatResponse, T>
108 where
109 C: StructuredOutputConverter<T>,
110 {
111 let resp_content = Bytes::from_static(b"bytes");
112 let entity = output_converter.convert(resp_content);
113 ResponseEntity {
114 response: todo!(),
115 entity,
116 }
117 }
118}
119
120impl CallResponseSpec for DefaultCallResponseSpec {
121 fn entity<T>(&self) -> T
122 where
123 T: DeserializeOwned,
124 {
125 todo!()
126 }
127
128 fn chat_response(&self) -> crate::chat::model::chat_response::ChatResponse {
129 todo!()
130 }
131
132 fn content(&self) -> Bytes {
133 todo!()
134 }
135
136 fn response_entity<T>(&self) -> T
137 where
138 T: DeserializeOwned,
139 {
140 todo!()
141 }
142}
143
144pub struct DefaultStreamResponseSpec {
145 request: DefaultChatClientRequestSpec,
146}
147
148#[async_trait]
149impl StreamResponseSpec for DefaultStreamResponseSpec {
150 async fn chat_response<S>(
151 &self,
152 ) -> impl futures_core::Stream<Item = ChatResponse> + Send + 'static {
153 futures_util::stream::empty()
154 }
155
156 async fn content<S>(&self) -> impl futures_core::Stream<Item = ChatResponse> + Send + 'static {
157 futures_util::stream::empty()
158 }
159}