next_web_ai/chat/client/
default_chat_client.rs

1use 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        // Options
31        spec.chat_options = prompt.chat_options().to_owned();
32
33        // Messages
34        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}