gemini_client_api/gemini/
utils.rs1use super::types::request::*;
2use crate::utils::{self, MatchedFiles};
3use getset::Getters;
4use regex::Regex;
5use reqwest::header::HeaderMap;
6use std::time::Duration;
7
8const REQ_TIMEOUT: Duration = Duration::from_secs(10);
9
10pub struct MarkdownToPartsBuilder {
11 regex: Option<Regex>,
12 guess_mime_type: Option<fn(url: &str) -> mime::Mime>,
13 decide_download: Option<fn(headers: &HeaderMap) -> bool>,
14 timeout: Option<Duration>,
15}
16impl MarkdownToPartsBuilder {
17 pub fn regex(mut self, regex: Regex) -> Self {
21 self.regex = Some(regex);
22 self
23 }
24 pub fn guess_mime_type(mut self, guess_mime_type: fn(url: &str) -> mime::Mime) -> Self {
27 self.guess_mime_type = Some(guess_mime_type);
28 self
29 }
30 pub fn decide_download(mut self, decide_download: fn(headers: &HeaderMap) -> bool) -> Self {
33 self.decide_download = Some(decide_download);
34 self
35 }
36 pub fn timeout(mut self, timeout: Duration) -> Self {
37 self.timeout = Some(timeout);
38 self
39 }
40 pub async fn build<'a>(self, markdown: &'a str) -> MarkdownToParts<'a> {
41 MarkdownToParts {
42 markdown,
43 base64s: utils::get_file_base64s(
44 markdown,
45 self.regex
46 .unwrap_or(Regex::new(r"(?s)!\[.*?].?\((.*?)\)").unwrap()),
47 self.guess_mime_type.unwrap_or(|_| mime::IMAGE_PNG),
48 |_| true,
49 self.timeout.unwrap_or(REQ_TIMEOUT),
50 )
51 .await,
52 }
53 }
54}
55#[derive(Getters, Clone)]
56pub struct MarkdownToParts<'a> {
58 markdown: &'a str,
59 #[get = "pub"]
60 base64s: Vec<MatchedFiles>,
61}
62impl<'a> MarkdownToParts<'a> {
63 pub fn builder() -> MarkdownToPartsBuilder {
64 MarkdownToPartsBuilder {
65 regex: None,
66 guess_mime_type: None,
67 decide_download: None,
68 timeout: None,
69 }
70 }
71 pub async fn from_regex_checked(
84 markdown: &'a str,
85 regex: Regex,
86 guess_mime_type: fn(url: &str) -> mime::Mime,
87 decide_download: fn(headers: &HeaderMap) -> bool,
88 ) -> Self {
89 Self {
90 base64s: utils::get_file_base64s(
91 markdown,
92 regex,
93 guess_mime_type,
94 decide_download,
95 REQ_TIMEOUT,
96 )
97 .await,
98 markdown,
99 }
100 }
101 pub async fn from_regex(
112 markdown: &'a str,
113 regex: Regex,
114 guess_mime_type: fn(url: &str) -> mime::Mime,
115 ) -> Self {
116 Self::from_regex_checked(markdown, regex, guess_mime_type, |_| true).await
117 }
118 pub async fn new_checked(
128 markdown: &'a str,
129 guess_mime_type: fn(url: &str) -> mime::Mime,
130 decide_download: fn(headers: &HeaderMap) -> bool,
131 ) -> Self {
132 let image_regex = Regex::new(r"(?s)!\[.*?].?\((.*?)\)").unwrap();
133 Self::from_regex_checked(markdown, image_regex, guess_mime_type, decide_download).await
134 }
135 pub async fn new(markdown: &'a str, guess_mime_type: fn(url: &str) -> mime::Mime) -> Self {
143 Self::new_checked(markdown, guess_mime_type, |_| true).await
144 }
145 pub fn process(mut self) -> Vec<Part> {
146 let mut parts: Vec<Part> = Vec::new();
147 let mut removed_length = 0;
148 for file in self.base64s {
149 if let MatchedFiles {
150 index,
151 length,
152 mime_type: Some(mime_type),
153 base64: Some(base64),
154 } = file
155 {
156 let end = index + length - removed_length;
157 let text = &self.markdown[..end];
158 parts.push(Part::text(text.to_string()));
159 parts.push(Part::inline_data(InlineData::new(mime_type, base64)));
160
161 self.markdown = &self.markdown[end..];
162 removed_length += end;
163 }
164 }
165 if self.markdown.len() != 0 {
166 parts.push(Part::text(self.markdown.to_string()));
167 }
168 parts
169 }
170}