use anyhow::Result; use serde::Deserialize; #[derive(Deserialize, Debug)] struct DdgResult { #[serde(rename = "Text")] text: Option, #[serde(rename = "FirstURL")] first_url: Option, } #[derive(Deserialize, Debug)] struct DdgResponse { #[serde(rename = "AbstractText")] abstract_text: Option, #[serde(rename = "RelatedTopics")] related_topics: Vec, } pub async fn search(client: &reqwest::Client, query: &str) -> Result { let url = format!( "https://api.duckduckgo.com/?q={}&format=json&no_html=1&skip_disambig=1", urlencoding::encode(query) ); let resp = client .get(&url) .header("User-Agent", "sovereign-35/1.0") .send() .await? .json::() .await?; let mut out = String::new(); if let Some(abs) = &resp.abstract_text { if !abs.is_empty() { out.push_str(&format!("DDG ABSTRACT: {}\n\n", abs)); } } for (i, r) in resp.related_topics.iter().take(3).enumerate() { if let (Some(text), Some(url)) = (&r.text, &r.first_url) { out.push_str(&format!("[DDG {}] {}\n{}\n\n", i + 1, text, url)); } } if out.is_empty() { out = "DDG: no results".to_string(); } Ok(out) }