How to Configure Custom OpenAI-Compatible Endpoints for AI Summaries in Meetily
Meetily routes summary requests to any OpenAI-compatible service by accepting a custom endpoint URL at runtime, which the Rust backend validates and appends with /chat/completions to generate meeting summaries.
The open-source meeting assistant Meetily (Zackriya-Solutions/meetily) decouples its summary engine from specific AI providers through a dynamic configuration system. When you configure custom OpenAI-compatible endpoints for summaries, the application forwards your requests to private LLMs, Azure OpenAI, or proxy services while maintaining the standard OpenAI API contract.
How the Custom Endpoint Integration Works
Meetily uses a three-layer architecture to process summary requests with configurable endpoints:
- Frontend invocation – TypeScript code calls the Tauri command
builtin_ai_generate_summarywith thecustomOpenAIEndpointparameter. - Command routing – The Rust handler in
src-tauri/src/summary/summary_engine/commands.rsforwards the endpoint to the LLM client. - Request construction – The
generate_summaryfunction insrc-tauri/src/summary/llm_client.rsbuilds the final URL by trimming trailing slashes and appending/chat/completions.
The endpoint is not hard-coded. The LLMProvider::CustomOpenAI variant expects the URL at runtime, allowing you to switch between OpenAI, self-hosted models, or compatible proxies without rebuilding the application.
Frontend Implementation: Calling the Tauri Command
To trigger a summary with a custom endpoint, invoke the builtin_ai_generate_summary command from your React or TypeScript frontend. Pass the provider identifier custom-openai and the full URL to your compatible API.
import { invoke } from '@tauri-apps/api/tauri';
/**
* Generate a summary using a private OpenAI-compatible service.
*/
async function generateSummaryViaCustomOpenAI(
transcript: string,
apiKey: string,
model = 'gpt-4',
endpoint = 'https://my-openai-proxy.example.com'
) {
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, // The custom endpoint URL
maxTokens: 1024,
temperature: 0.7,
topP: 0.9,
});
return result; // Returns the generated summary text
}
The customOpenAIEndpoint value is passed as an optional string to the Rust backend, where it becomes the base URL for all subsequent API calls.
Backend Handler: Routing to the LLM Client
On the Rust side, the builtin_ai_generate_summary command in src-tauri/src/summary/summary_engine/commands.rs receives the endpoint and forwards it to the core generation logic. The command signature accepts custom_openai_endpoint as an Option<String> and passes it directly to the LLM client without modification.
#[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();
// Forward the optional endpoint to the core generator
summary::llm_client::generate_summary(
&client,
&provider,
&model_name,
&api_key,
&system_prompt,
&user_prompt,
None, // ollama_endpoint – not used here
custom_openai_endpoint.as_deref(),
max_tokens,
temperature,
top_p,
None, // app_data_dir – not needed for remote service
None, // cancellation token
)
.await
}
This handler ensures that when the LLMProvider is CustomOpenAI, the optional endpoint URL propagates to the HTTP client logic.
LLM Client URL Construction
The actual HTTP request construction happens in src-tauri/src/summary/llm_client.rs. Lines 173-179 handle the URL formatting for custom endpoints by trimming any trailing slashes and appending the standard OpenAI chat completions path.
// From src-tauri/src/summary/llm_client.rs
let url = format!(
"{}/chat/completions",
endpoint.trim_end_matches('/')
);
This implementation guarantees that whether you provide https://api.example.com, https://api.example.com/, or https://api.example.com/v1, the resulting request targets https://api.example.com/chat/completions (or https://api.example.com/v1/chat/completions respectively).
Persisting Settings Between Sessions
Meetily stores user-defined configuration in JSON format within the application data directory. When you update the "Custom OpenAI endpoint" field in the settings UI, the application writes the value to the internal config store (managed in src-tauri/src/config.rs).
The persisted JSON structure follows this pattern:
{
"summary": {
"customOpenAIEndpoint": "https://my-openai-proxy.example.com"
}
}
On subsequent summary requests, the frontend reads this stored value and passes it as the customOpenAIEndpoint argument to the Tauri command, ensuring your custom endpoint persists across application restarts.
Summary
- Dynamic routing: Meetily accepts custom OpenAI-compatible endpoints at runtime via the
customOpenAIEndpointparameter inbuiltin_ai_generate_summary. - URL handling: The backend automatically formats the endpoint by trimming trailing slashes and appending
/chat/completionsinsrc-tauri/src/summary/llm_client.rs. - Provider selection: Use the provider string
custom-openaito trigger the custom endpoint logic in theLLMProviderenum. - Persistence: Endpoint settings are stored in JSON configuration files within the app data directory and retrieved automatically for each summary generation request.
Frequently Asked Questions
What URL format should I use for the custom endpoint?
Provide the base URL of your OpenAI-compatible service without the /chat/completions path. According to the source code in src-tauri/src/summary/llm_client.rs, the backend automatically handles trailing slashes. For example, use https://api.example.com/v1 or https://api.example.com—both resolve correctly to {endpoint}/chat/completions.
Is the API key sent directly to the custom endpoint?
Yes. The api_key parameter you pass to builtin_ai_generate_summary is included in the Authorization header of the HTTP request sent to your custom endpoint. The backend does not filter or modify the key, so ensure your endpoint implements standard OpenAI authentication expectations.
Can I use Azure OpenAI or other OpenAI-compatible services?
Absolutely. Meetily's LLMProvider::CustomOpenAI variant works with any service implementing the OpenAI chat completions API schema, including Azure OpenAI, Ollama with OpenAI compatibility mode, or custom proxies. Simply provide the appropriate endpoint URL and model name when calling the summary command.
Where are the custom endpoint settings stored?
User settings are persisted in JSON files within the application's data directory, managed through src-tauri/src/config.rs. The specific key summary.customOpenAIEndpoint stores your custom URL, which the frontend retrieves and passes to the Rust backend during each summary generation request.
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 →