How to Configure a Custom OpenAI-Compatible Endpoint for AI Summaries in Meetily

You can route Meetily's AI summary generation to any OpenAI-compatible service by setting the customOpenAIEndpoint parameter in the builtin_ai_generate_summary Tauri command, which dynamically constructs the request URL in llm_client.rs rather than using a hard-coded constant.

Meetily's architecture supports private or hosted Large Language Models (LLMs) through a flexible provider system that accepts custom endpoints at runtime. This allows you to integrate Azure OpenAI, private self-hosted models, or third-party proxies without modifying the Rust backend source code.

Architecture Overview

Meetily's summary flow uses a three-stage pipeline to decouple the frontend from the specific LLM implementation:

  1. Frontend invocation – React/TypeScript components call the Tauri runtime with configuration arguments
  2. Command routing – builtin_ai_generate_summary in the Rust backend validates parameters and instantiates the LLM client
  3. Dynamic URL construction – The generate_summary function in src-tauri/src/summary/llm_client.rs (lines 173-179) builds the final HTTP endpoint by appending /chat/completions to your custom base URL

When the provider argument resolves to LLMProvider::CustomOpenAI, the system expects a valid HTTP URL in the custom_openai_endpoint parameter. The backend trims trailing slashes and constructs the final request path automatically.

Step-by-Step Implementation

Frontend Configuration (TypeScript)

Your React components invoke the Tauri command through the @tauri-apps/api package. You must specify 'custom-openai' as the provider string and include your endpoint URL:

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

/**
 * Generates a meeting summary using a private OpenAI-compatible API.
 */
async function summarizeWithCustomEndpoint(
  transcript: string,
  apiKey: string,
  endpoint: string = 'https://my-openai-proxy.example.com'
): Promise<string> {
  return await invoke<string>('builtin_ai_generate_summary', {
    provider: 'custom-openai',           // Maps to LLMProvider::CustomOpenAI
    modelName: 'gpt-4',
    apiKey: apiKey,
    systemPrompt: 'You are a concise meeting summary assistant.',
    userPrompt: transcript,
    customOpenAIEndpoint: endpoint,      // Your custom base URL
    maxTokens: 1024,
    temperature: 0.7,
    topP: 0.9,
  });
}

The customOpenAIEndpoint value is passed directly to the Rust backend as an optional string parameter.

Tauri Command Routing

The builtin_ai_generate_summary command in src-tauri/src/summary/summary_engine/commands.rs acts as the bridge between the frontend and the LLM client. It accepts the optional endpoint and forwards it to the core generation logic:

#[tauri::command]
pub async fn builtin_ai_generate_summary(
    provider: String,
    model_name: String,
    api_key: String,
    system_prompt: String,
    user_prompt: String,
    custom_openai_endpoint: Option<String>,
    // ...additional optional parameters...
) -> Result<String, String> {
    let provider = LLMProvider::from_str(&provider)?;
    let client = reqwest::Client::new();

    summary::llm_client::generate_summary(
        &client,
        &provider,
        &model_name,
        &api_key,
        &system_prompt,
        &user_prompt,
        None,                       // ollama_endpoint (not used)
        custom_openai_endpoint.as_deref(),
        max_tokens,
        temperature,
        top_p,
        None,                       // app_data_dir
        None,                       // cancellation token
    )
    .await
}

This command handles the provider enum conversion and HTTP client instantiation before delegating to the summary generator.

LLM Client URL Construction

The actual HTTP request construction occurs in src-tauri/src/summary/llm_client.rs at lines 173-179. When processing a CustomOpenAI provider, the code dynamically builds the API endpoint:

format!("{}/chat/completions", endpoint.trim_end_matches('/'))

This implementation ensures that whether you provide https://api.example.com or https://api.example.com/, the resulting URL correctly resolves to https://api.example.com/chat/completions without double slashes.

Persisting Endpoint Configuration

To avoid hardcoding endpoints in your frontend components, Meetily stores user preferences in JSON format within the application's data directory (managed by src-tauri/src/config.rs). A typical settings structure looks like:

{
  "summary": {
    "customOpenAIEndpoint": "https://my-openai-proxy.example.com",
    "customOpenAIKey": "sk-..."
  }
}

Your settings UI should read this configuration on startup and pass the stored value as the customOpenAIEndpoint argument whenever calling builtin_ai_generate_summary.

Key Source File References

The integration relies on three specific components:

Summary

  • Dynamic routing: Meetily does not hard-code OpenAI URLs; the endpoint is supplied at runtime through the custom_openai_endpoint parameter
  • Provider selection: You must use the provider string 'custom-openai' (case-sensitive) to trigger the custom endpoint logic in llm_client.rs
  • URL construction: The backend automatically handles trailing slashes and appends /chat/completions to your base URL
  • Persistence: Store the endpoint in the app's JSON settings under the summary.customOpenAIEndpoint key to avoid repeated configuration

Frequently Asked Questions

What format should the custom endpoint URL use?

Provide the base URL without the /chat/completions suffix. For example, use https://api.openai.com or https://my-azure-instance.openai.azure.com/openai/deployments/my-deployment. The Rust code in llm_client.rs automatically appends /chat/completions and removes any trailing slashes from your input.

Can I use Azure OpenAI Service with this configuration?

Yes. Azure OpenAI is compatible with this implementation as long as you provide the full deployment URL including the /openai/deployments/{deployment-id} path segment. Pass this as the customOpenAIEndpoint parameter along with your Azure API key in the apiKey field.

Is the API key sent securely to the custom endpoint?

The API key is transmitted via HTTPS in the request headers to your specified endpoint, using the same Authorization: Bearer {key} format as standard OpenAI requests. Ensure your custom endpoint uses TLS/SSL, as the reqwest client in the Rust backend enforces HTTPS for security.

How do I troubleshoot connection errors to my custom endpoint?

Check the Tauri backend logs for the constructed URL. The generate_summary function in llm_client.rs will fail at the HTTP request stage if the URL is malformed or unreachable. Verify that your endpoint responds to POST /chat/completions with a JSON body matching the OpenAI Chat Completions API schema.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →