How to Configure a Custom OpenAI-Compatible Endpoint for AI Summaries in Meetily
Meetily routes AI summary requests to a custom OpenAI-compatible endpoint by passing the URL at runtime to the builtin_ai_generate_summary Tauri command, which concatenates the endpoint with /chat/completions in the Rust backend.
Meetily's architecture supports any OpenAI-compatible API—including private hosted models, Azure OpenAI, or third-party proxies—without hard-coding URLs. The endpoint configuration flows from the React frontend through a Tauri command to the LLM client, where the request URL is constructed dynamically. This guide walks through the implementation details in the Zackriya-Solutions/meetily repository.
How the Custom Endpoint Flow Works
When you trigger an AI summary with a custom provider, the request follows a three-stage pipeline:
- Frontend invocation: The React UI calls the Tauri command
builtin_ai_generate_summarywith thecustomOpenAIEndpointparameter. - Command routing: The Rust command handler in
src-tauri/src/summary/summary_engine/commands.rsforwards the endpoint to the LLM client. - URL construction: In
src-tauri/src/summary/llm_client.rs, thegenerate_summaryfunction validates theLLMProvider::CustomOpenAIvariant and builds the final request URL by appending/chat/completionsto your custom endpoint.
The endpoint is never stored as a compile-time constant; it is always supplied at runtime through the custom_openai_endpoint argument.
Backend Implementation: The LLM Client
The core logic resides in src-tauri/src/summary/llm_client.rs. When the provider is set to CustomOpenAI, the generate_summary function constructs the API URL by trimming trailing slashes and appending the chat completions path:
// Lines 173-179 of llm_client.rs
let url = format!("{}/chat/completions", endpoint.trim_end_matches('/'));
This ensures compatibility with endpoints that may or may not include a trailing slash. The function then uses reqwest to POST the JSON payload to this constructed URL, passing the api_key in the Authorization header exactly as it would for the standard OpenAI API.
The Tauri command that exposes this functionality to the frontend is defined in src-tauri/src/summary/summary_engine/commands.rs:
#[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>,
// ... other optional args
) -> 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
custom_openai_endpoint.as_deref(), // <-- custom endpoint passed here
max_tokens,
temperature,
top_p,
None, // app_data_dir
None, // cancellation token
)
.await
}
Frontend Integration: Calling the Tauri Command
From the React frontend, you invoke the command using @tauri-apps/api/tauri. You must specify the provider as "custom-openai" (which maps to LLMProvider::CustomOpenAI) and include the customOpenAIEndpoint parameter:
import { invoke } from '@tauri-apps/api/tauri';
/**
* Generate a summary using a private OpenAI-compatible service.
*/
async function generateSummaryViaCustomOpenAI(
transcript: string,
apiKey: string,
model: string = 'gpt-4',
endpoint: string = 'https://my-openai-proxy.example.com'
): Promise<string> {
const result = await invoke<string>('builtin_ai_generate_summary', {
provider: 'custom-openai', // Maps to LLMProvider::CustomOpenAI
modelName: model,
apiKey,
systemPrompt: 'You are a concise meeting-summary assistant.',
userPrompt: transcript,
customOpenAIEndpoint: endpoint, // Your custom endpoint URL
maxTokens: 1024,
temperature: 0.7,
topP: 0.9,
});
return result;
}
The customOpenAIEndpoint value is passed directly to the Rust command as the custom_openai_endpoint parameter, which then flows into the LLM client.
Persisting the Configuration
To avoid passing the endpoint manually each time, Meetily stores user-defined settings in a JSON file within the application data directory. The settings structure includes a summary object with a customOpenAIEndpoint field:
{
"summary": {
"customOpenAIEndpoint": "https://my-openai-proxy.example.com"
}
}
When the settings UI updates this value, the frontend reads from this store before invoking the Tauri command. The configuration constants and file paths are defined in src-tauri/src/config.rs, while the UI implementation resides in the React components under frontend/src/app.
Summary
- Runtime configuration: The custom OpenAI-compatible endpoint is supplied at runtime via the
custom_openai_endpointparameter, not hard-coded. - URL construction: In
src-tauri/src/summary/llm_client.rs, Meetily builds the final URL as{endpoint}/chat/completionsafter trimming trailing slashes. - Command interface: Use the
builtin_ai_generate_summaryTauri command withprovider: 'custom-openai'to trigger the custom endpoint logic. - Persistence: Store the endpoint in Meetily's internal JSON settings to automatically include it in future summary requests.
Frequently Asked Questions
What format should the custom endpoint URL follow?
The endpoint should point to the base URL of your OpenAI-compatible API without the /chat/completions path. For example, use https://api.my-company.com/v1 rather than https://api.my-company.com/v1/chat/completions. Meetily automatically appends the completions path in llm_client.rs.
Can I use Azure OpenAI with this configuration?
Yes. Azure OpenAI Service is compatible with this approach as long as you provide the full Azure endpoint URL (including the deployment path) and the appropriate API key. The generate_summary function treats all CustomOpenAI providers identically, sending standard OpenAI-formatted JSON payloads.
Where does Meetily store my custom endpoint settings?
Meetily persists settings in a JSON file located in the application data directory, managed through the configuration layer in src-tauri/src/config.rs. The specific field customOpenAIEndpoint under the summary key holds your custom URL, which the frontend reads before invoking the Tauri command.
Is the API key sent securely to the custom endpoint?
The API key is passed as a string parameter to the Tauri command and included in the Authorization header (Bearer {api_key}) by the generate_summary function in src-tauri/src/summary/llm_client.rs. Ensure your custom endpoint uses HTTPS to encrypt the key in transit, as Meetily does not modify or encrypt the key beyond standard HTTP TLS.
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 →