tarzi 0.2.3

Rust-native lite search for AI applications
Documentation
Quick Start Guide
=================

This guide will get you up and running with tarzi in just a few minutes. 
We'll cover the most common use cases and basic functionality.

.. note::
   tarzi supports only Linux and macOS. Windows is not supported.

Your First tarzi Program
-------------------------

Python
~~~~~~

Let's start with a simple example that demonstrates the core functionality:

.. code-block:: python

   import tarzi

   # 1. Convert HTML to Markdown
   html = "<h1>Hello World</h1><p>This is a <strong>test</strong>.</p>"
   markdown = tarzi.convert_html(html, "markdown")
   print("Converted to Markdown:")
   print(markdown)

   # 2. Fetch a web page (plain HTTP → headless browser)
   try:
       content = tarzi.fetch_url(
           "https://httpbin.org/html",
           format="markdown"
       )
       print("\nFetched content:")
       print(content[:200] + "...")
   except Exception as e:
       print(f"Fetch failed: {e}")

   # 3. Search the web (uses config: API → plain HTTP → browser)
   try:
       results = tarzi.search_web("python web scraping", limit=3)
       print(f"\nFound {len(results)} search results:")
       for i, result in enumerate(results):
           print(f"{i+1}. {result.title}")
           print(f"   URL: {result.url}")
           print(f"   Snippet: {result.snippet[:100]}...")
   except Exception as e:
       print(f"Search failed: {e}")

   # 4. Search via Brave API when BRAVE_API_KEY / search.api_key is set
   try:
       config = tarzi.Config.from_str(
           "[search]\nengine = \"brave\"\nbrowser = true\nlimit = 3\n"
       )
       engine = tarzi.SearchEngine.from_config(config)
       results = engine.search("machine learning trends", 3)
       print(f"\nFound {len(results)} results:")
       for i, result in enumerate(results):
           print(f"{i+1}. {result.title}")
           print(f"   URL: {result.url}")
   except Exception as e:
       print(f"Configured search failed: {e}")

Save this as `quickstart.py` and run it:

.. code-block:: bash

   python quickstart.py

Rust
~~~~

Here's the equivalent Rust program:

.. code-block:: rust

   use tarzi::{config::Config, Converter, WebFetcher, SearchEngine, Format};

   #[tokio::main]
   async fn main() -> Result<(), Box<dyn std::error::Error>> {
       // 1. Convert HTML to Markdown
       let converter = Converter::new();
       let html = "<h1>Hello World</h1><p>This is a <strong>test</strong>.</p>";
       let markdown = converter.convert(html, Format::Markdown).await?;
       println!("Converted to Markdown:\n{}", markdown);

       // 2. Fetch a web page
       let mut fetcher = WebFetcher::new();
       match fetcher.fetch(
           "https://httpbin.org/html",
           Format::Markdown
       ).await {
           Ok(content) => {
               println!("\nFetched content:\n{}...", &content[..200.min(content.len())]);
           }
           Err(e) => println!("Fetch failed: {}", e),
       }

       // 3. Search the web (API → plain HTTP → browser)
       let mut search_engine = SearchEngine::new();
       match search_engine.search("agentic AI", 3).await {
           Ok(results) => {
               println!("\nFound {} search results:", results.len());
               for (i, result) in results.iter().enumerate() {
                   println!("{}. {}", i + 1, result.title);
                   println!("   URL: {}", result.url);
                   println!("   Snippet: {}...", &result.snippet[..100.min(result.snippet.len())]);
               }
           }
           Err(e) => println!("Search failed: {}", e),
       }

       // 4. Prefer Brave API when a key is configured
       let mut config = Config::new();
       config.search.engine = "brave".to_string();
       config.search.browser = true;
       let mut api_search_engine = SearchEngine::from_config(&config);
       match api_search_engine.search("machine learning trends", 3).await {
           Ok(results) => {
               println!("\nFound {} results:", results.len());
               for (i, result) in results.iter().enumerate() {
                   println!("{}. {}", i + 1, result.title);
                   println!("   URL: {}", result.url);
               }
           }
           Err(e) => println!("Configured search failed: {}", e),
       }

       Ok(())
   }

Save this as `src/main.rs` in a new Cargo project and run:

.. code-block:: bash

   cargo run

CLI
~~~

You can also use the command-line interface:

.. code-block:: bash

   # Convert HTML to Markdown
   tarzi convert --input "<h1>Hello</h1>" --format markdown

   # Fetch a web page
   tarzi fetch --url "https://httpbin.org/html" --format markdown

   # Search the web
   tarzi search --query "agentic AI" --limit 3

Core Concepts
-------------

Formats
~~~~~~~

tarzi supports multiple output formats:

- **Markdown**: Clean, readable text format
- **JSON**: Structured data with metadata
- **YAML**: Human-readable structured format

.. code-block:: python

   # Try different formats
   html = "<h1>Title</h1><p>Content with <a href='#'>link</a>.</p>"
   
   markdown = tarzi.convert_html(html, "markdown")
   json_data = tarzi.convert_html(html, "json")
   yaml_data = tarzi.convert_html(html, "yaml")
   
   print("Markdown:", markdown)
   print("JSON:", json_data)
   print("YAML:", yaml_data)

Fetch Cascade
~~~~~~~~~~~

Fetch always tries plain HTTP first, then headless browser when enabled:


.. code-block:: python

   # Cascade (plain HTTP → headless browser)
   content = tarzi.fetch_url(
       "https://example.com",
       format="markdown"
   )

   # Disable browser fallback via config
   config = tarzi.Config.load()
   config.set_fetcher_browser(False)
   content = tarzi.WebFetcher.from_config(config).fetch(
       "https://example.com",
       "html"
   )

Search Access Cascade
~~~~~~~~~~~~~~~~~~~~~

Access cascade is always on:

- **API**: when credentials are present
- **plain HTTP**: public SERP URL
- **browser**: when ``search.browser`` / ``TARZI_SEARCH_BROWSER`` is true (default)

Supported engines: ``duckduckgo,bing,brave`` (default failover), ``google``, ``google_serper`` (alias ``serper``),
``baidu``, ``sogou_weixin``, plus API-only ``tavily``, ``googleai``, ``searxng``.

API Search Providers
~~~~~~~~~~~~~~~~~~~~

- **Brave** (``brave``): ``BRAVE_API_KEY`` or ``search.api_key``
- **Google Serper** (``google_serper`` / ``serper``): ``SERPER_API_KEY`` or ``search.api_key``

.. code-block:: python

   # Uses configured cascade
   results = tarzi.search_web("machine learning", limit=10)

   # Serper API via config
   config = tarzi.Config.from_str(
       "[search]\nengine = \"google_serper\"\nbrowser = false\n"
   )
   engine = tarzi.SearchEngine.from_config(config)
   results = engine.search("artificial intelligence", 10)

   # Multi-engine failover without browser
   config = tarzi.Config.from_str(
       "[search]\nengine = \"brave,duckduckgo\"\nbrowser = false\n"
   )
   engine = tarzi.SearchEngine.from_config(config)
   results = engine.search("rust async", 5)

Configuration
-------------

**Breaking change:** ``tarzi.toml`` / ``~/.tarzi.toml`` / ``Config.from_file`` are removed.
Configure with environment variables (see ``.env.example``):

.. code-block:: bash

   export TARZI_SEARCH_ENGINE=brave
   export TARZI_SEARCH_BROWSER=true
   export TARZI_SEARCH_LIMIT=5
   export TARZI_USER_AGENT="Mozilla/5.0 (compatible; Tarzi/1.0)"
   export TARZI_FETCHER_TIMEOUT=30
   # Engine API keys only (no TARZI_API_KEY):
   # export BRAVE_API_KEY=... / SERPER_API_KEY=...
   # Optional: export TARZI_PROXY=http://proxy.example.com:8080
   # Or standard: export HTTPS_PROXY=... / HTTP_PROXY=...

Environment Variables
~~~~~~~~~~~~~~~~~~~~~

.. code-block:: bash

   # Proxy configuration (standard environment variables)
   export http_proxy=http://proxy.example.com:8080
   export https_proxy=http://proxy.example.com:8080

   # Search API keys
   export BRAVE_API_KEY=your-brave-api-key
   export SERPER_API_KEY=your-serper-api-key

   # Debug mode (for development/testing)
   export TARZI_DEBUG=1

Next Steps
----------

- Read the configuration and development guides for detailed usage patterns
- Check out the :doc:`examples/index` for more examples
- Explore the :doc:`python_api/index` or :doc:`rust_api/index` for API reference
- Configure advanced options in :doc:`configuration`