How to Integrate a New AI Provider (Ollama, Claude, Groq, OpenRouter) into Meetily's Summary Engine
To integrate a new AI provider into Meetily's summary engine, extend the LLMProvider enum in 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– Defines theLLMProviderenum (lines 66‑76), implementsfrom_strparsing 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– Orchestrates the summarization workflow, decides between single-pass and chunked processing based on the selected provider, and forwards provider-specific options such asollama_endpointorcustom_openapi_endpoint(lines 400‑508). -
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:
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:
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:
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:
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 and update the call site in processor.rs. The existing pattern for ollama_endpoint and custom_openapi_endpoint demonstrates how to forward optional configuration:
// 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:
// 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:
// 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:
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) to include the new option:
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
LLMProviderinllm_client.rsand implementFromStrparsing 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_summarymatch block (lines 151‑188). - Update logging – Add a friendly name to the
provider_namehelper for observability. - Expose configuration – Forward any custom endpoints or parameters through the Tauri command layer in
processor.rs. - Maintain cancellation safety – All providers automatically inherit the
CancellationTokensupport implemented in thetokio::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, 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →