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:
- Frontend invocation – React/TypeScript components call the Tauri runtime with configuration arguments
- Command routing –
builtin_ai_generate_summaryin the Rust backend validates parameters and instantiates the LLM client - Dynamic URL construction – The
generate_summaryfunction insrc-tauri/src/summary/llm_client.rs(lines 173-179) builds the final HTTP endpoint by appending/chat/completionsto 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:
frontend/src-tauri/src/summary/llm_client.rs– Contains the URL construction logic (lines 173-179) that appends/chat/completionsto your custom base URLfrontend/src-tauri/src/summary/summary_engine/commands.rs– Houses thebuiltin_ai_generate_summaryTauri command that receives frontend requestsfrontend/src-tauri/src/config.rs– Defines the app-data directory paths where persistent settings are stored
Summary
- Dynamic routing: Meetily does not hard-code OpenAI URLs; the endpoint is supplied at runtime through the
custom_openai_endpointparameter - Provider selection: You must use the provider string
'custom-openai'(case-sensitive) to trigger the custom endpoint logic inllm_client.rs - URL construction: The backend automatically handles trailing slashes and appends
/chat/completionsto your base URL - Persistence: Store the endpoint in the app's JSON settings under the
summary.customOpenAIEndpointkey 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →