web_search/providers/
registry.rs1use serde::Serialize;
11
12use super::base::SearchProvider;
13use super::bing::{BingConfig, BingProvider};
14use super::duckduckgo::DuckDuckGoProvider;
15use super::engines::{access_for, all_descriptor_engines, EngineDescriptor};
16use super::generic::GenericProvider;
17use super::google::{GoogleConfig, GoogleProvider};
18use super::web_capture::{WebCaptureProvider, SUPPORTED_PROVIDERS};
19
20pub const CATEGORIES: [&str; 4] = ["search", "knowledge", "papers", "code"];
22
23#[derive(Debug, Clone, Serialize)]
25#[serde(rename_all = "camelCase")]
26pub struct RegistryEntry {
27 pub id: String,
29 pub label: String,
31 pub category: String,
33 pub cors_readable: bool,
35 pub default_for_category: bool,
37 pub access: String,
39}
40
41#[derive(Debug, Clone, Default)]
43pub struct BuildConfig {
44 pub google_api_key: Option<String>,
46 pub google_cx: Option<String>,
48 pub bing_api_key: Option<String>,
50}
51
52struct ClassEngine {
55 id: &'static str,
56 label: &'static str,
57 category: &'static str,
58 cors_readable: bool,
59 default_for_category: bool,
60 access: &'static str,
61}
62
63const CLASS_ENGINES: [ClassEngine; 3] = [
64 ClassEngine {
65 id: "google",
66 label: "Google",
67 category: "search",
68 cors_readable: false,
69 default_for_category: true,
70 access: "hybrid",
71 },
72 ClassEngine {
73 id: "bing",
74 label: "Bing",
75 category: "search",
76 cors_readable: false,
77 default_for_category: false,
78 access: "hybrid",
79 },
80 ClassEngine {
81 id: "duckduckgo",
82 label: "DuckDuckGo",
83 category: "search",
84 cors_readable: false,
85 default_for_category: false,
86 access: "html",
87 },
88];
89
90fn descriptor_entry(d: &EngineDescriptor) -> RegistryEntry {
91 RegistryEntry {
92 id: d.id.to_string(),
93 label: d.label.to_string(),
94 category: d.category.to_string(),
95 cors_readable: d.cors_readable,
96 default_for_category: d.default_for_category,
97 access: access_for(d.kind).to_string(),
98 }
99}
100
101pub fn get_registry() -> Vec<RegistryEntry> {
104 let mut entries = Vec::new();
105
106 for e in &CLASS_ENGINES {
107 entries.push(RegistryEntry {
108 id: e.id.to_string(),
109 label: e.label.to_string(),
110 category: e.category.to_string(),
111 cors_readable: e.cors_readable,
112 default_for_category: e.default_for_category,
113 access: e.access.to_string(),
114 });
115 }
116 for d in all_descriptor_engines() {
117 entries.push(descriptor_entry(&d));
118 }
119 for engine in SUPPORTED_PROVIDERS {
120 entries.push(RegistryEntry {
121 id: format!("wc:{engine}"),
122 label: format!("web-capture ({engine})"),
123 category: "search".to_string(),
124 cors_readable: engine == "wikipedia",
125 default_for_category: false,
126 access: "component".to_string(),
127 });
128 }
129
130 entries
131}
132
133pub fn get_provider_ids(category: Option<&str>) -> Vec<String> {
135 get_registry()
136 .into_iter()
137 .filter(|e| category.is_none_or(|c| e.category == c))
138 .map(|e| e.id)
139 .collect()
140}
141
142pub fn get_default_provider_ids() -> Vec<String> {
144 ["duckduckgo", "google", "bing", "wikipedia"]
145 .iter()
146 .map(|s| s.to_string())
147 .collect()
148}
149
150pub fn is_known_category(category: &str) -> bool {
152 CATEGORIES.contains(&category)
153}
154
155pub fn build_providers(config: &BuildConfig) -> Vec<(String, Box<dyn SearchProvider>)> {
157 let mut providers: Vec<(String, Box<dyn SearchProvider>)> = Vec::new();
158
159 providers.push((
160 "google".to_string(),
161 Box::new(GoogleProvider::new(GoogleConfig {
162 api_key: config.google_api_key.clone(),
163 search_engine_id: config.google_cx.clone(),
164 })),
165 ));
166 providers.push((
167 "bing".to_string(),
168 Box::new(BingProvider::new(BingConfig {
169 api_key: config.bing_api_key.clone(),
170 })),
171 ));
172 providers.push((
173 "duckduckgo".to_string(),
174 Box::new(DuckDuckGoProvider::new()),
175 ));
176
177 for d in all_descriptor_engines() {
178 providers.push((d.id.to_string(), Box::new(GenericProvider::new(d))));
179 }
180
181 for engine in SUPPORTED_PROVIDERS {
182 providers.push((
183 format!("wc:{engine}"),
184 Box::new(WebCaptureProvider::new(engine)),
185 ));
186 }
187
188 providers
189}