# How to Integrate a New AI Provider (Ollama, Claude, Groq, OpenRouter) into Meetily's Summary Engine

> Learn how to integrate new AI providers like Ollama Claude Groq and OpenRouter into Meetily's summary engine by extending the LLMProvider enum and configuring HTTP endpoints and headers.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: how-to-guide
- Published: 2026-07-31

---

**To integrate a new AI provider into Meetily's summary engine, extend the `LLMProvider` enum in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs), add a string parsing branch to `from_str`, map the variant to its HTTP endpoint and authentication headers in the `generate_summary` method, and expose any configuration options through the Tauri command layer.**

Meetily's meeting summarization pipeline is provider-agnostic by design, allowing seamless integration of LLM services including local Ollama instances and cloud providers like Claude, Groq, and OpenRouter. The modular Rust backend in the `Zackriya-Solutions/meetily` repository separates provider-specific HTTP logic from the core summarization algorithm, making it straightforward to add support for additional AI services without modifying the underlying chunking or cancellation mechanisms.

## Understanding the Provider Architecture

The integration surface consists of three core components that handle provider recognition, request construction, and orchestration.

### Core Files and Responsibilities

- **[`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs)** – Defines the `LLMProvider` enum (lines **66‑76**), implements `from_str` parsing to recognize provider names like `"ollama"` or `"claude"`, and constructs HTTP requests with provider-specific endpoints and headers (lines **151‑188**).

- **[`frontend/src-tauri/src/summary/processor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/processor.rs)** – Orchestrates the summarization workflow, decides between single-pass and chunked processing based on the selected provider, and forwards provider-specific options such as `ollama_endpoint` or `custom_openapi_endpoint` (lines **400‑508**).

- **[`frontend/src-tauri/src/api/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/api/commands.rs)** – Exposes Tauri commands that bridge the frontend UI to the Rust backend, passing user-selected provider strings and API keys into the processor.

### The Provider Interface Pattern

The engine abstracts every LLM behind a unified `generate_summary` function that returns `Result<String, String>`. This function uses a `match` statement to route requests to the correct endpoint while maintaining **cancellation safety** through a `tokio::select!` block (lines **666‑682**). The processor additionally implements a **chunking strategy** that triggers multi-pass summarization for local providers like `Ollama` and `BuiltInAI` when processing long transcripts.

## Step-by-Step Integration Guide

Follow these steps to add a new provider such as a custom OpenAI-compatible endpoint or a proprietary API.

### 1. Extend the LLMProvider Enum

Add your provider variant to the enum definition in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs):

```rust
pub enum LLMProvider {
    OpenAI,
    Claude,
    Groq,
    Ollama,
    OpenRouter,
    BuiltInAI,
    CustomOpenAI,
    MyCustomAI,  // Add new variant here
}

```

### 2. Implement String Parsing

Update the `from_str` implementation (lines **66‑76**) to resolve the provider name from the UI into the enum variant:

```rust
impl FromStr for LLMProvider {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "openai" => Ok(Self::OpenAI),
            "claude" => Ok(Self::Claude),
            "groq" => Ok(Self::Groq),
            "ollama" => Ok(Self::Ollama),
            "openrouter" => Ok(Self::OpenRouter),
            "mycustomai" => Ok(Self::MyCustomAI),  // Add parsing branch
            _ => Err(format!("Unsupported LLM provider: {}", s)),
        }
    }
}

```

### 3. Configure Endpoint and Headers

Extend the `match provider` block in `generate_summary` (lines **151‑188**) to define the base URL and authentication headers:

```rust
let (base_url, headers) = match provider {
    LLMProvider::Ollama => (
        ollama_endpoint.clone().unwrap_or_else(|| "http://localhost:11434/v1/chat/completions".to_string()),
        HeaderMap::new(),  // No auth header for local Ollama
    ),
    LLMProvider::Claude => (
        "https://api.anthropic.com/v1/messages".to_string(),
        {
            let mut h = HeaderMap::new();
            h.insert("x-api-key", api_key.parse()?);
            h.insert("anthropic-version", "2023-06-01".parse()?);
            h
        },
    ),
    LLMProvider::Groq => (
        "https://api.groq.com/openai/v1/chat/completions".to_string(),
        HeaderMap::new(),  // Bearer token added generically below
    ),
    LLMProvider::OpenRouter => (
        "https://openrouter.ai/api/v1/chat/completions".to_string(),
        HeaderMap::new(),
    ),
    LLMProvider::MyCustomAI => (
        "https://api.mycustomai.com/v1/chat".to_string(),
        {
            let mut h = HeaderMap::new();
            h.insert("x-api-key", api_key.parse()?);
            h.insert("x-client-version", "2024-01".parse()?);
            h
        },
    ),
    _ => return Err("Unsupported provider configuration".to_string()),
};

```

### 4. Add Logging Support

Update the `provider_name` helper method (lines **335‑345**) to ensure logs display a friendly name:

```rust
fn provider_name(provider: &LLMProvider) -> &'static str {
    match provider {
        LLMProvider::Ollama => "Ollama",
        LLMProvider::Claude => "Claude",
        LLMProvider::Groq => "Groq",
        LLMProvider::OpenRouter => "OpenRouter",
        LLMProvider::MyCustomAI => "MyCustomAI",  // Add logging name
        _ => "Unknown",
    }
}

```

### 5. Expose Configuration to the Frontend

If your provider requires custom endpoints or model-specific parameters, extend the Tauri command signature in [`frontend/src-tauri/src/api/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/api/commands.rs) and update the call site in [`processor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/processor.rs). The existing pattern for `ollama_endpoint` and `custom_openapi_endpoint` demonstrates how to forward optional configuration:

```rust
// In processor.rs - generate_meeting_summary function
pub async fn generate_meeting_summary(
    provider: &LLMProvider,
    model_name: &str,
    api_key: &str,
    ollama_endpoint: Option<String>,
    custom_openapi_endpoint: Option<String>,
    mycustomai_endpoint: Option<String>,  // Add new parameter
) -> Result<String, String> {
    // Forward to generate_summary
}

```

### 6. Handle Authentication

Most cloud providers use `Bearer` token authentication. The generic implementation adds this header automatically for all providers except Claude (which uses `x-api-key`). If your provider requires a custom scheme, add it in the specific match arm before the generic header insertion:

```rust
// After the match block, generic auth header injection
if provider != &LLMProvider::Claude && provider != &LLMProvider::MyCustomAI {
    headers.insert(
        header::AUTHORIZATION,
        HeaderValue::from_str(&format!("Bearer {}", api_key))?,
    );
}

```

## Complete Integration Example

Here is the complete implementation for adding a hypothetical "Perplexity" provider to Meetily's summary engine:

```rust
// frontend/src-tauri/src/summary/llm_client.rs

// 1. Add variant
pub enum LLMProvider {
    // ... existing variants
    Perplexity,
}

// 2. Add parsing
impl FromStr for LLMProvider {
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            // ... existing cases
            "perplexity" => Ok(Self::Perplexity),
            _ => Err(format!("Unsupported LLM provider: {}", s)),
        }
    }
}

// 3. Add endpoint and headers in generate_summary
match provider {
    // ... existing providers
    LLMProvider::Perplexity => (
        "https://api.perplexity.ai/chat/completions".to_string(),
        HeaderMap::new(),  // Uses standard Bearer auth
    ),
}

// 4. Add logging name
fn provider_name(provider: &LLMProvider) -> &'static str {
    match provider {
        // ... existing cases
        LLMProvider::Perplexity => "Perplexity",
    }
}

```

## Frontend Integration

Invoke the new provider from the React/TypeScript frontend using Tauri's command system:

```typescript
import { invoke } from '@tauri-apps/api/tauri';

async function generateSummary(transcript: string) {
  try {
    const summary = await invoke<string>('generate_meeting_summary', {
      provider: 'perplexity',
      modelName: 'llama-3.1-sonar-large-128k-online',
      apiKey: process.env.PERPLEXITY_API_KEY,
      transcript: transcript,
      // Pass undefined for unsupported options
      ollamaEndpoint: undefined,
      customOpenaiEndpoint: undefined,
    });
    return summary;
  } catch (error) {
    console.error('Summary generation failed:', error);
  }
}

```

Update the provider dropdown in your React components (e.g., [`frontend/src/components/MeetingDetails/SummarySettings.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/components/MeetingDetails/SummarySettings.tsx)) to include the new option:

```typescript
const providers = [
  { value: 'openai', label: 'OpenAI' },
  { value: 'claude', label: 'Claude' },
  { value: 'groq', label: 'Groq' },
  { value: 'ollama', label: 'Ollama (Local)' },
  { value: 'openrouter', label: 'OpenRouter' },
  { value: 'perplexity', label: 'Perplexity' },  // Add here
];

```

## Provider-Specific Implementation Details

### Ollama Integration

Ollama runs locally and requires no authentication. The engine checks for a custom `ollama_endpoint` parameter, defaulting to `http://localhost:11434/v1/chat/completions`. Because Ollama models often have smaller context windows, the processor automatically enables **chunking mode** for long transcripts when this provider is selected.

### Claude Integration

Anthropic's Claude API uses a non-standard endpoint (`/v1/messages`) and requires the `x-api-key` and `anthropic-version` headers. The implementation bypasses the generic Bearer token injection for this provider.

### Groq and OpenRouter

Both providers implement OpenAI-compatible chat completion endpoints. Groq uses `https://api.groq.com/openai/v1/chat/completions`, while OpenRouter uses `https://openrouter.ai/api/v1/chat/completions`. These receive standard Bearer token authentication and support the full range of OpenAI-compatible parameters.

## Summary

- **Extend the enum** – Add a variant to `LLMProvider` in [`llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/llm_client.rs) and implement `FromStr` parsing to recognize the provider name from the UI.
- **Configure the HTTP client** – Map the variant to its base URL and required headers in the `generate_summary` match block (lines **151‑188**).
- **Update logging** – Add a friendly name to the `provider_name` helper for observability.
- **Expose configuration** – Forward any custom endpoints or parameters through the Tauri command layer in [`processor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/processor.rs).
- **Maintain cancellation safety** – All providers automatically inherit the `CancellationToken` support implemented in the `tokio::select!` block at lines **666‑682**.

## Frequently Asked Questions

### How do I add a provider that isn't in the existing list?

Extend the `LLMProvider` enum with a new variant, add a corresponding branch to the `from_str` implementation in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs), and define the endpoint and headers in the `generate_summary` match statement. No changes are required to the core summarization algorithm.

### Can I use a local endpoint with cloud providers?

Yes. The `custom_openapi_endpoint` parameter in [`processor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/processor.rs) demonstrates the pattern for overriding default URLs. You can add similar optional parameters for any provider to support proxy configurations or on-premise deployments.

### How does the engine handle different authentication schemes?

The generic implementation applies `Bearer` token authentication to all providers except Claude. If your provider uses a custom header scheme (like `x-api-key`), add the headers in the specific provider's match arm and exclude that provider from the generic Bearer token injection logic.

### What testing strategy should I use for new providers?

Add unit tests in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs) to verify that `LLMProvider::from_str` correctly parses your provider string and that the `generate_summary` function constructs the expected URL and headers. The existing test suite for Ollama, Claude, Groq, and OpenRouter provides a template for validating provider-specific request construction.