How to Add a Custom OpenAI-Compatible Endpoint for AI Summaries in Meetily
Set a custom OpenAI-compatible endpoint by passing customOpenAIEndpoint to the builtin_ai_generate_summary Tauri command, which routes requests to {endpoint}/chat/completions via the LLM client in src-tauri/src/summary/llm_client.rs.
Meetily's summarization system is designed to work with any OpenAI-compatible API, including private proxies, Azure OpenAI deployments, or self-hosted models like vLLM. The backend does not hard-code provider URLs; instead, it accepts a dynamic endpoint parameter at runtime. This guide walks through the complete flow—from frontend invocation to request construction—so you can integrate your own AI infrastructure.
Understanding the Architecture
Meetily uses a three-layer architecture for summary generation:
- Frontend (React/TypeScript) – Gathers user input and settings, then invokes the Tauri command.
- Tauri command layer – Receives arguments, validates the provider type, and delegates to the LLM client.
- LLM client (
llm_client.rs) – Constructs the HTTP request using the provided endpoint.
The critical integration point is the custom_openai_endpoint parameter, which the LLM client appends to /chat/completions when provider is "custom-openai".
Calling the Tauri Command from the Frontend
The frontend triggers summary generation via Tauri's invoke API. Pass the provider name "custom-openai" and your endpoint URL as arguments.
import { invoke } from '@tauri-apps/api/tauri';
/**
* Generate a meeting summary through a private OpenAI-compatible service.
*/
async function summarizeWithCustomEndpoint(
transcript: string,
apiKey: string,
customEndpoint: string,
model = 'gpt-4'
): Promise<string> {
const summary = await invoke<string>('builtin_ai_generate_summary', {
provider: 'custom-openai',
modelName: model,
apiKey,
systemPrompt: 'Summarize this meeting transcript concisely.',
userPrompt: transcript,
customOpenAIEndpoint: customEndpoint,
maxTokens: 1024,
temperature: 0.7,
topP: 0.9,
});
return summary;
}
// Example usage
const result = await summarizeWithCustomEndpoint(
meetingTranscript,
'sk-your-api-key',
'https://my-internal-openai.example.com'
);
Key parameters:
provider: 'custom-openai'– Required to trigger theLLMProvider::CustomOpenAIbranch in Rust.customOpenAIEndpoint– The base URL of your OpenAI-compatible service (no trailing/chat/completionsneeded).
How the Rust Backend Processes the Request
The builtin_ai_generate_summary command in src-tauri/src/summary/summary_engine/commands.rs receives the frontend arguments and forwards them to the core generator.
#[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
custom_openai_endpoint.as_deref(), // <-- passed here
// ...remaining parameters
)
.await
}
The custom_openai_endpoint is passed as Option<&str> to the generator, allowing None for non-custom providers.
URL Construction in the LLM Client
In src-tauri/src/summary/llm_client.rs (lines 173-179), the client builds the complete request URL:
let url = format!(
"{}/chat/completions",
endpoint.trim_end_matches('/')
);
This means your endpoint should be the base URL only. For example:
| Your Input | Constructed URL |
|---|---|
https://api.internal.com |
https://api.internal.com/chat/completions |
https://api.internal.com/ |
https://api.internal.com/chat/completions |
https://api.internal.com/v1 |
https://api.internal.com/v1/chat/completions |
The trim_end_matches('/') ensures consistent URL construction regardless of whether you include a trailing slash.
Persisting the Endpoint in Settings
To avoid passing the endpoint on every call, Meetily stores user preferences in JSON within the app-data directory. The settings structure includes:
{
"summary": {
"aiProvider": "custom-openai",
"customOpenAIEndpoint": "https://my-openai-proxy.example.com",
"customOpenAIModel": "gpt-4",
"customOpenAIApiKey": "sk-..."
}
}
When the settings UI updates this configuration, subsequent summary requests automatically read customOpenAIEndpoint and include it in the builtin_ai_generate_summary invocation.
Validating Your Custom Endpoint
Before integrating, verify your endpoint implements the OpenAI chat completions API:
- HTTP method:
POST - Path:
/chat/completions(appended by Meetily) - Headers:
Authorization: Bearer {apiKey},Content-Type: application/json - Request body: Standard OpenAI chat format with
model,messages,max_tokens,temperature,top_p - Response: JSON with
choices[0].message.content
Test with curl before configuring Meetily:
curl -X POST https://your-endpoint.com/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello"}],
"max_tokens": 50
}'
Summary
- Meetily supports custom OpenAI-compatible endpoints through the
custom-openaiprovider type. - Pass your endpoint URL as
customOpenAIEndpointto thebuiltin_ai_generate_summaryTauri command. - The LLM client in
src-tauri/src/summary/llm_client.rsconstructs the full URL by appending/chat/completionsto your base endpoint. - Store persistent configuration in Meetily's settings JSON to avoid manual parameter passing.
- No backend rebuild is required—the endpoint is resolved at runtime per request.
Frequently Asked Questions
What provider name should I use for a custom OpenAI-compatible endpoint?
Use custom-openai as the provider value. This maps to LLMProvider::CustomOpenAI in the Rust code, which activates the custom endpoint logic. Other valid providers include "openai", "ollama", and "anthropic", but only "custom-openai" respects the customOpenAIEndpoint parameter.
Does Meetily support Azure OpenAI with this method?
Yes. Azure OpenAI Service exposes an OpenAI-compatible REST API. Set customOpenAIEndpoint to your Azure endpoint (e.g., https://your-resource.openai.azure.com/openai/deployments/your-deployment-name) and include your Azure API key in the apiKey parameter. Ensure your deployment name matches the modelName you specify.
Can I use a local model like vLLM or llama.cpp-server?
Absolutely. Self-hosted OpenAI-compatible servers work identically to remote ones. Use http://localhost:8000 or your local server address as customOpenAIEndpoint. For servers without authentication, pass any non-empty string as apiKey—Meetily requires the parameter but your server may ignore it.
Where does Meetily store the custom endpoint configuration?
Meetily persists settings in a JSON file within the platform-specific app-data directory, managed through src-tauri/src/config.rs. The settings UI writes to this store, and frontend components read the customOpenAIEndpoint value when calling builtin_ai_generate_summary. You can also modify this file directly when Meetily is not running.
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 →