gemini_client_api/gemini/utils.rs
1use super::types::request::*;
2use crate::utils::{self, MatchedFiles};
3use regex::Regex;
4use reqwest::header::HeaderMap;
5
6///Converts markdown to parts considering `` means Gemini will be see the images too. `link` can be URL or file path.
7pub struct MarkdownToParts<'a> {
8 base64s: Vec<MatchedFiles>,
9 markdown: &'a str,
10}
11impl<'a> MarkdownToParts<'a> {
12 ///# Panics `regex` must have a Regex with only 1 capture group with file URL as first capture
13 ///group, else it PANICS.
14 /// # Arguments
15 /// `guess_mime_type` is used to detect mimi_type of URL pointing to file system or web resource
16 /// with no "Content-Type" header.
17 /// `decice_download` is used to decide if to download. If it returns false, resource will not
18 /// be fetched and won't be in `parts`
19 /// # Example
20 /// ```ignore
21 /// from_regex("Your markdown string...", Regex::new(r"(?s)!\[.*?].?\((.*?)\)").unwrap(), |_| mime::IMAGE_PNG, |_| true)
22 /// ```
23 pub async fn from_regex_checked(
24 markdown: &'a str,
25 regex: Regex,
26 guess_mime_type: fn(url: &str) -> mime::Mime,
27 decice_download: fn(headers: &HeaderMap) -> bool,
28 ) -> Self {
29 Self {
30 base64s: utils::get_file_base64s(markdown, regex, guess_mime_type, decice_download)
31 .await,
32 markdown,
33 }
34 }
35 ///# Panics
36 /// `regex` must have a Regex with only 1 capture group with file URL as first capture group, else it PANICS.
37 /// # Arguments
38 /// `guess_mime_type` is used to detect mimi_type of URL pointing to file system or web resource
39 /// with no "Content-Type" header.
40 /// # Example
41 /// ```ignore
42 /// from_regex("Your markdown string...", Regex::new(r"(?s)!\[.*?].?\((.*?)\)").unwrap(), |_|
43 /// mime::IMAGE_PNG)
44 /// ```
45 pub async fn from_regex(
46 markdown: &'a str,
47 regex: Regex,
48 guess_mime_type: fn(url: &str) -> mime::Mime,
49 ) -> Self {
50 Self::from_regex_checked(markdown, regex, guess_mime_type, |_| true).await
51 }
52 /// # Arguments
53 /// `guess_mime_type` is used to detect mimi_type of URL pointing to file system or web resource
54 /// with no "Content-Type" header.
55 /// `decice_download` is used to decide if to download. If it returns false, resource will not
56 /// be fetched and won't be in `parts`
57 /// # Example
58 /// ```ignore
59 /// new("Your markdown string...", |_| mime::IMAGE_PNG, |_| true)
60 /// ```
61 pub async fn new_checked(
62 markdown: &'a str,
63 guess_mime_type: fn(url: &str) -> mime::Mime,
64 decice_download: fn(headers: &HeaderMap) -> bool,
65 ) -> Self {
66 let image_regex = Regex::new(r"(?s)!\[.*?].?\((.*?)\)").unwrap();
67 Self::from_regex_checked(markdown, image_regex, guess_mime_type, decice_download).await
68 }
69 /// # Arguments
70 /// `guess_mime_type` is used to detect mimi_type of URL pointing to file system or web resource
71 /// with no "Content-Type" header.
72 /// # Example
73 /// ```ignore
74 /// new("Your markdown string...", |_| mime::IMAGE_PNG)
75 /// ```
76 pub async fn new(markdown: &'a str, guess_mime_type: fn(url: &str) -> mime::Mime) -> Self {
77 Self::new_checked(markdown, guess_mime_type, |_| true).await
78 }
79 pub fn process(mut self) -> Vec<Part> {
80 let mut parts: Vec<Part> = Vec::new();
81 let mut removed_length = 0;
82 for file in self.base64s {
83 if let MatchedFiles {
84 index,
85 length,
86 mime_type: Some(mime_type),
87 base64: Some(base64),
88 } = file
89 {
90 let end = index + length - removed_length;
91 let text = &self.markdown[..end];
92 parts.push(Part::text(text.to_string()));
93 parts.push(Part::inline_data(InlineData::new(mime_type, base64)));
94
95 self.markdown = &self.markdown[end..];
96 removed_length += end;
97 }
98 }
99 if self.markdown.len() != 0 {
100 parts.push(Part::text(self.markdown.to_string()));
101 }
102 parts
103 }
104}