use firecrawl::{extract::ExtractParams, FirecrawlApp};use serde_json::json;use std::error::Error; use clap::{Parser, ValueEnum}; #[derive(Parser)]#[command(author, version, about, long_about = None)]struct Args { #[arg(value_enum)] command: Examples,} #[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]enum Examples { Basic, Schema, JsonSchema,} #[tokio::main]async fn main() -> Result<(), Box<dyn Error>> { let args = Args::parse(); let api_url = std::env::var("FIRECRAWL_API_URL") .expect("Please set the FIRECRAWL_API_URL environment variable"); let firecrawl = FirecrawlApp::new_selfhosted(api_url, None::<&str>)?; let urls = vec![ "https://www.firecrawl.dev/".to_string(), "https://betteruptime.com".to_string(), ]; match args.command { Examples::Basic => { println!("Example 1: Extracting with URLs and prompt"); let extract_params = ExtractParams { prompt: Some( "Extract Product promise, consice descirption and category".to_string(), ), url_trace: Some(true), ..Default::default() }; println!("Starting asynchronous extraction job..."); let response = firecrawl .async_extract(ExtractParams { urls: Some(urls.iter().map(|u| u.to_string()).collect()), prompt: extract_params.prompt.clone(), url_trace: extract_params.url_trace, ..Default::default() }) .await?; println!("Extract job initiated:"); println!(" Job ID: {}", response.id); println!("\nChecking extract status..."); for _ in 0..5 { let response = firecrawl.get_extract_status(&response.id).await?; println!("Extract status: {}", response.status); if let Some(url_trace) = &response.url_trace { println!("URL traces:"); for trace in url_trace { println!(" URL: {}", trace.url); println!(" Status: {}", trace.status); } } println!("Extract data: {:#?}", response.data); if response.status == "completed" { break; } tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; } } Examples::Schema => { println!("Example 2: Extracting with schema"); let schema = json!({ "type": "object", "properties": { "category": { "type": "string" }, "promise": { "type": "string" }, "descirption": { "type": "string" } }, "required": ["category", "promise", "description"] }); println!("Starting synchronous extraction job..."); match firecrawl .extract(ExtractParams { urls: urls.into(), schema: Some(schema), ..Default::default() }) .await { Ok(result) => { println!("Extraction completed successfully!"); println!("Status: {}", result.status); if let Some(data) = result.data { println!("\nExtracted data:"); println!(" Title: {}", data["title"]); if let Some(desc) = data.get("description") { println!(" Description: {}", desc); } println!( " Content (preview): {:.100}...", data["content"].as_str().unwrap_or("N/A") ); } if let Some(sources) = result.sources { println!("\nSources:"); for (field, urls) in sources { println!(" {}: {}", field, urls.join(", ")); } } } Err(e) => { println!("Extraction failed: {}", e); } } } Examples::JsonSchema => { println!("Example 3: Using JsonSchema derive"); /// A comprehensive analysis of given product #[derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)] struct ProductAnalysis { /// The full name of the product product_name: String, /// The company/brand behind the product brand: String, /// The general price range (e.g. "Premium", "$10-50", "Enterprise") price_range: String, /// The main customer segments this product targets target_audience: Vec<String>, /// Primary benefits and value propositions of the product key_benefits: Vec<String>, /// Distinctive features that set this product apart from competitors unique_selling_points: Vec<String>, /// Direct comparisons with competing products/services competitor_comparison: Vec<String>, /// Technologies, frameworks, or platforms used (if applicable) tech_stack: Option<Vec<String>>, /// Aggregated review data and sentiment analysis reviews_summary: ReviewsSummary, // /// Score from 0-10 indicating product-market fit based on analysis // market_fit_score: f32, // NOTE: Breaks /// Assessment of future growth prospects (e.g. "High", "Moderate", "Limited") growth_potential: String, /// Relevant compliance standards and certifications regulatory_compliance: Option<Vec<String>>, } /// Aggregated analysis of product reviews from multiple sources #[derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)] struct ReviewsSummary { /// Overall sentiment from review analysis (e.g. "Highly Positive", "Mixed", "Negative") sentiment_analysis: String, /// Most frequently mentioned positive aspects common_praises: Vec<String>, /// Most frequently mentioned criticisms or issues common_complaints: Vec<String>, /// Platforms or websites where reviews were sourced from review_sources: Vec<String>, } println!("Starting extraction with derived schema..."); match firecrawl .extract_with_schemars::<ProductAnalysis>(ExtractParams { urls: urls.into(), ..Default::default() }) .await { Ok(result) => { println!("Extraction completed!"); println!("Status: {}", result.status); if let Some(data) = result.data { if let Ok(analysis) = serde_json::from_value::<ProductAnalysis>(data) { println!("\nExtracted Product Analysis:"); println!(" Product: {}", analysis.product_name); println!(" Brand: {}", analysis.brand); println!(" Price Range: {}", analysis.price_range); println!(" Target Audience:"); for audience in analysis.target_audience { println!(" - {}", audience); } println!(" Key Benefits:"); for benefit in analysis.key_benefits { println!(" - {}", benefit); } println!(" USPs:"); for usp in analysis.unique_selling_points { println!(" - {}", usp); } println!("\n Reviews Summary:"); println!( " Sentiment: {}", analysis.reviews_summary.sentiment_analysis ); println!(" Common Praises:"); for praise in analysis.reviews_summary.common_praises { println!(" - {}", praise); } println!(" Common Complaints:"); for complaint in analysis.reviews_summary.common_complaints { println!(" - {}", complaint); } } else { println!("Failed to parse extracted data"); } } if let Some(sources) = result.sources { println!("\nSources:"); for (field, urls) in sources { println!(" {}: {}", field, urls.join(", ")); } } } Err(e) => { println!("Extraction failed: {}", e); } } } } Ok(())}
use firecrawl::{extract::ExtractParams, FirecrawlApp};
use serde_json::json;
use std::error::Error;
use clap::{Parser, ValueEnum};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(value_enum)]
command: Examples,
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
enum Examples {
Basic,
Schema,
JsonSchema,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let api_url = std::env::var("FIRECRAWL_API_URL")
.expect("Please set the FIRECRAWL_API_URL environment variable");
let firecrawl = FirecrawlApp::new_selfhosted(api_url, None::<&str>)?;
let urls = vec![
"https://www.firecrawl.dev/".to_string(),
"https://betteruptime.com".to_string(),
];
match args.command {
Examples::Basic => {
println!("Example 1: Extracting with URLs and prompt");
let extract_params = ExtractParams {
prompt: Some(
"Extract Product promise, consice descirption and category".to_string(),
),
url_trace: Some(true),
..Default::default()
};
println!("Starting asynchronous extraction job...");
let response = firecrawl
.async_extract(ExtractParams {
urls: Some(urls.iter().map(|u| u.to_string()).collect()),
prompt: extract_params.prompt.clone(),
url_trace: extract_params.url_trace,
..Default::default()
})
.await?;
println!("Extract job initiated:");
println!(" Job ID: {}", response.id);
println!("\nChecking extract status...");
for _ in 0..5 {
let response = firecrawl.get_extract_status(&response.id).await?;
println!("Extract status: {}", response.status);
if let Some(url_trace) = &response.url_trace {
println!("URL traces:");
for trace in url_trace {
println!(" URL: {}", trace.url);
println!(" Status: {}", trace.status);
}
}
println!("Extract data: {:#?}", response.data);
if response.status == "completed" {
break;
}
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
}
}
Examples::Schema => {
println!("Example 2: Extracting with schema");
let schema = json!({
"type": "object",
"properties": {
"category": { "type": "string" },
"promise": { "type": "string" },
"descirption": { "type": "string" }
},
"required": ["category", "promise", "description"]
});
println!("Starting synchronous extraction job...");
match firecrawl
.extract(ExtractParams {
urls: urls.into(),
schema: Some(schema),
..Default::default()
})
.await
{
Ok(result) => {
println!("Extraction completed successfully!");
println!("Status: {}", result.status);
if let Some(data) = result.data {
println!("\nExtracted data:");
println!(" Title: {}", data["title"]);
if let Some(desc) = data.get("description") {
println!(" Description: {}", desc);
}
println!(
" Content (preview): {:.100}...",
data["content"].as_str().unwrap_or("N/A")
);
}
if let Some(sources) = result.sources {
println!("\nSources:");
for (field, urls) in sources {
println!(" {}: {}", field, urls.join(", "));
}
}
}
Err(e) => {
println!("Extraction failed: {}", e);
}
}
}
Examples::JsonSchema => {
println!("Example 3: Using JsonSchema derive");
/// A comprehensive analysis of given product
#[derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
struct ProductAnalysis {
/// The full name of the product
product_name: String,
/// The company/brand behind the product
brand: String,
/// The general price range (e.g. "Premium", "$10-50", "Enterprise")
price_range: String,
/// The main customer segments this product targets
target_audience: Vec<String>,
/// Primary benefits and value propositions of the product
key_benefits: Vec<String>,
/// Distinctive features that set this product apart from competitors
unique_selling_points: Vec<String>,
/// Direct comparisons with competing products/services
competitor_comparison: Vec<String>,
/// Technologies, frameworks, or platforms used (if applicable)
tech_stack: Option<Vec<String>>,
/// Aggregated review data and sentiment analysis
reviews_summary: ReviewsSummary,
// /// Score from 0-10 indicating product-market fit based on analysis
// market_fit_score: f32, // NOTE: Breaks
/// Assessment of future growth prospects (e.g. "High", "Moderate", "Limited")
growth_potential: String,
/// Relevant compliance standards and certifications
regulatory_compliance: Option<Vec<String>>,
}
/// Aggregated analysis of product reviews from multiple sources
#[derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
struct ReviewsSummary {
/// Overall sentiment from review analysis (e.g. "Highly Positive", "Mixed", "Negative")
sentiment_analysis: String,
/// Most frequently mentioned positive aspects
common_praises: Vec<String>,
/// Most frequently mentioned criticisms or issues
common_complaints: Vec<String>,
/// Platforms or websites where reviews were sourced from
review_sources: Vec<String>,
}
println!("Starting extraction with derived schema...");
match firecrawl
.extract_with_schemars::<ProductAnalysis>(ExtractParams {
urls: urls.into(),
..Default::default()
})
.await
{
Ok(result) => {
println!("Extraction completed!");
println!("Status: {}", result.status);
if let Some(data) = result.data {
if let Ok(analysis) = serde_json::from_value::<ProductAnalysis>(data) {
println!("\nExtracted Product Analysis:");
println!(" Product: {}", analysis.product_name);
println!(" Brand: {}", analysis.brand);
println!(" Price Range: {}", analysis.price_range);
println!(" Target Audience:");
for audience in analysis.target_audience {
println!(" - {}", audience);
}
println!(" Key Benefits:");
for benefit in analysis.key_benefits {
println!(" - {}", benefit);
}
println!(" USPs:");
for usp in analysis.unique_selling_points {
println!(" - {}", usp);
}
println!("\n Reviews Summary:");
println!(
" Sentiment: {}",
analysis.reviews_summary.sentiment_analysis
);
println!(" Common Praises:");
for praise in analysis.reviews_summary.common_praises {
println!(" - {}", praise);
}
println!(" Common Complaints:");
for complaint in analysis.reviews_summary.common_complaints {
println!(" - {}", complaint);
}
} else {
println!("Failed to parse extracted data");
}
}
if let Some(sources) = result.sources {
println!("\nSources:");
for (field, urls) in sources {
println!(" {}: {}", field, urls.join(", "));
}
}
}
Err(e) => {
println!("Extraction failed: {}", e);
}
}
}
}
Ok(())
}