ragit_api/
lib.rs

1use ragit_fs::{WriteMode, read_string, write_string};
2
3mod api_provider;
4mod error;
5mod json_type;
6mod message;
7mod model;
8pub mod record;
9mod request;
10mod response;
11
12pub use crate::api_provider::ApiProvider;
13pub use crate::error::Error;
14pub use crate::json_type::JsonType;
15pub use crate::message::message_contents_to_json_array;
16pub use crate::model::{Model, ModelRaw, get_model_by_name};
17pub use crate::record::RecordAt;
18pub use crate::request::Request;
19pub use crate::response::Response;
20
21pub use ragit_pdl::{
22    ImageType,
23    Message,
24    MessageContent,
25    Role,
26    Schema,
27};
28
29pub fn load_models(json_path: &str) -> Result<Vec<Model>, Error> {
30    let models = read_string(json_path)?;
31    let models: Vec<ModelRaw> = serde_json::from_str(&models)?;
32    let mut result = Vec::with_capacity(models.len());
33
34    for model in models.iter() {
35        result.push(Model::try_from(model)?);
36    }
37
38    Ok(result)
39}
40
41pub fn save_models(models: &[Model], path: &str) -> Result<(), Error> {
42    let models: Vec<ModelRaw> = models.iter().map(|model| model.into()).collect();
43    Ok(write_string(
44        path,
45        &serde_json::to_string_pretty(&models)?,
46        WriteMode::CreateOrTruncate,
47    )?)
48}
49
50#[cfg(test)]
51mod tests {
52    use crate::{ModelRaw, Request};
53    use ragit_fs::{
54        WriteMode,
55        create_dir_all,
56        current_dir,
57        remove_dir_all,
58        write_bytes,
59        write_string,
60    };
61    use ragit_pdl::{Pdl, parse_pdl, parse_pdl_from_file};
62
63    #[tokio::test]
64    async fn media_pdl_test() {
65        // path relative to pdl file
66        let pdl1 = "
67<|user|>
68
69What do you see in this picture?
70
71<|media(../images/sample.webp)|>
72";
73        // path relative to pwd
74        let pdl2 = "
75<|user|>
76
77What do you see in this picture?
78
79<|media(__tmp_pdl_test/images/sample.webp)|>
80";
81
82        create_dir_all("__tmp_pdl_test/pdl").unwrap();
83        create_dir_all("__tmp_pdl_test/images").unwrap();
84        let image_file = include_bytes!("../../../tests/images/hello_world.webp");
85        write_string("__tmp_pdl_test/pdl/sample1.pdl", pdl1, WriteMode::AlwaysCreate).unwrap();
86        write_bytes("__tmp_pdl_test/images/sample.webp", image_file, WriteMode::AlwaysCreate).unwrap();
87
88        let Pdl { messages: messages1, .. } = parse_pdl_from_file(
89            "__tmp_pdl_test/pdl/sample1.pdl",
90            &tera::Context::new(),
91            true,
92            true,
93        ).unwrap();
94        let Pdl { messages: messages2, .. } = parse_pdl(
95            pdl2,
96            &tera::Context::new(),
97            &current_dir().unwrap(),
98            true,
99            true,
100        ).unwrap();
101
102        for messages in [messages1, messages2] {
103            let request = Request {
104                model: (&ModelRaw::gpt_4o_mini()).try_into().unwrap(),
105                messages,
106                ..Request::default()
107            };
108            let response = request.send().await.unwrap().get_message(0).unwrap().to_ascii_lowercase();
109
110            // TODO: it's pratically correct, but not formally correct
111            assert!(response.contains("hello"));
112            assert!(response.contains("world"));
113        }
114
115        remove_dir_all("__tmp_pdl_test").unwrap();
116    }
117}